# How OpenHuman Classifies Commands and Gates Permissions for Agent Actions

> OpenHuman classifies shell commands and gates permissions for agent actions using a deterministic, fail-closed security architecture. Learn how it assesses risk and prevents unauthorized actions.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: how-to-guide
- Published: 2026-08-27

---

**OpenHuman employs a deterministic, fail-closed security architecture that parses every shell command into classified segments, assesses risk levels, and applies tier-based permission gates to prevent unauthorized agent actions.**

In the OpenHuman framework—available at `tinyhumansai/openhuman`—agent autonomy is controlled through a sophisticated policy engine written in Rust. This system treats every shell command as a classified operation, applying structural guards and risk assessments before execution to ensure agents operate within defined safety boundaries.

## The Three-Layer Security Model

The permission system operates through three distinct phases defined in the core security policy modules. According to the OpenHuman source code, each command passes through parsing, risk analysis, and gating logic before reaching the execution layer.

| Phase | Core Function | Source File |
|-------|--------------|-------------|
| **Classification** | Tokenizes commands, normalizes executables, maps to `CommandClass` | [`src/openhuman/security/policy/policy_command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy/policy_command.rs) |
| **Risk Assessment** | Evaluates `CommandRiskLevel` against catastrophic and medium-risk patterns | [`src/openhuman/security/policy/command_checks.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy/command_checks.rs) |
| **Permission Gating** | Applies `AutonomyLevel` constraints to produce `GateDecision` outcomes | [`src/openhuman/security/policy/command_checks.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy/command_checks.rs) |

## Command Parsing and Classification

The classification pipeline begins in [`policy_command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/policy_command.rs), where the `classify_command` function transforms raw shell strings into structured, categorized operations. This process involves several deterministic steps that sanitize and analyze command structure.

### Segment Parsing and Normalization

The `split_unquoted_segments` function tokenizes command lines on unquoted delimiters—including `;`, `|`, `&&`, `||`, and newlines—while respecting single and double quotes. This prevents injection attacks that rely on delimiter collision.

Environment variable assignments are stripped via `skip_env_assignments`, which removes leading `NAME=value` fragments. The system treats any leading assignment as suspicious through `has_leading_env_assignment` and specifically flags dangerous prefixes via `has_dangerous_env_prefix`.

Executable names undergo normalization through `normalized_command_name`, which lower-cases the basename and strips trailing `.exe` extensions to ensure consistent classification across platforms.

### Command Class Mapping

The `classify_segment` function in [`policy_command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/policy_command.rs) maps normalized executables to `CommandClass` variants using hard-coded allow-lists:

- **`READ_ONLY_BASES`** → `CommandClass::Read` (safe inspection tools)
- **`NETWORK_BASES`** → `CommandClass::Network` (connectivity utilities)
- **`DESTRUCTIVE_BASES`** → `CommandClass::Destructive` (disk formatting, system shutdown)
- **Install detection** via `is_install_command` → `CommandClass::Install` (package managers)
- **Interpreter detection** via `is_command_executor` → `CommandClass::Write` (shells, scripting languages)

When no pattern matches, the system defaults to `CommandClass::Write`, implementing a fail-closed posture that assumes potential side effects.

### Structural Safety Guards

Before classification completes, `has_hidden_execution` checks for dangerous shell constructs including backticks, `$(...)` or `<(...)` expansions, and unquoted background operators (`&`). These structural guards prevent command obfuscation techniques that could bypass policy enforcement.

## Risk Assessment and Threat Detection

Once classified, commands undergo risk scoring in [`command_checks.rs`](https://github.com/tinyhumansai/openhuman/blob/main/command_checks.rs) through the `command_risk_level` method. This evaluation determines whether a command represents a catastrophic threat, moderate risk, or safe operation.

### High-Risk Pattern Detection

The system flags commands as **High** risk when they match catastrophic executable names or contain destructive substrings. This includes system-level utilities like `mkfs`, `dd`, `shutdown`, and `sudo`, as well as known dangerous patterns such as `rm -rf /` or fork bombs like `:(){:|:&};:`.

### Medium-Risk Classification

State-changing but non-catastrophic operations receive **Medium** risk ratings. The `command_risk_level` implementation identifies these through patterns including:

- Version control mutations (`git push`)
- Package installation (`npm install`)
- File-system modification utilities (`chmod`, `chown`)
- Network data transfer tools (`curl`, `wget`)

All other commands default to **Low** risk, allowing efficient fast-path processing for read-only operations.

## Permission Gating and Autonomy Tiers

The final security layer applies user-configured autonomy constraints through the `gate_decision` method. OpenHuman defines three `AutonomyLevel` variants that determine the gating behavior: `ReadOnly`, `Supervised`, and `Full`.

### The Gate Decision Matrix

The `gate_decision` function implements the following permission matrix:

| Autonomy Tier | Allowed Classes | Prompted Classes | Blocked Classes |
|---------------|----------------|------------------|-----------------|
| **ReadOnly** | `Read` | — | `Write`, `Network`, `Install`, `Destructive` |
| **Supervised** | `Read` | `Write`, `Network`, `Install`, `Destructive` | — |
| **Full** | `Read`, `Write` | `Network`, `Install`, `Destructive` | — |

In **ReadOnly** mode, agents can only execute read-classified commands, with all modification attempts blocked immediately. **Supervised** mode requires explicit user approval for any non-read operation, while **Full** mode permits write operations automatically but still prompts on network, installation, and destructive classes.

### Validation and Enforcement

The `check_gated_command` method enforces structural constraints for non-Full tiers, invoking `has_hidden_execution` to prevent subshell escapes. For supervised and read-only modes, `is_command_allowed` implements strict allow-list validation that rejects unknown executables, dangerous arguments (such as `find -exec` or `git config` mutations), unquoted redirections (`>`), and background operators.

The `validate_command_execution` function serves as the final checkpoint, respecting configuration flags like `require_approval_for_medium_risk` and `block_high_risk_commands` to determine whether execution proceeds or returns a `POLICY_BLOCKED_MARKER` error.

## Practical Implementation Examples

Below are concrete examples demonstrating the classification and gating API as implemented in the OpenHuman crate:

```rust
use openhuman::security::policy::{SecurityPolicy, AutonomyLevel};

// Initialize a supervised security policy
let mut policy = SecurityPolicy::default();
policy.autonomy = AutonomyLevel::Supervised;

// Classify a version control command
let cmd = "git push origin main";
let class = policy.classify_command(cmd);
// Returns: CommandClass::Write

// Evaluate gating decision
let decision = policy.gate_decision(class);
// Returns: GateDecision::Prompt (requires user approval in Supervised mode)

```

The following example demonstrates risk evaluation for system-level commands:

```rust
// Assess catastrophic command risk
let dangerous_cmd = "mkfs.ext4 /dev/sda1";
let risk = policy.command_risk_level(dangerous_cmd);
// Returns: CommandRiskLevel::High

// Validation respects block_high_risk_commands default
match policy.validate_command_execution(dangerous_cmd, false) {
    Ok(level) => println!("Approved with risk: {:?}", level),
    Err(e) => println!("Policy rejection: {}", e),
    // Typically rejects unless explicit approval provided
}

```

Structural guards prevent hidden execution attempts regardless of classification:

```rust
// Detects subshell injection
let obfuscated = "echo $(rm -rf /)";
assert!(has_hidden_execution(obfuscated)); // Returns true, triggering block

```

## Summary

OpenHuman's command classification and permission gating system provides deterministic safety through:

- **Deterministic classification** via `classify_segment` and normalized executable mapping in [`policy_command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/policy_command.rs)
- **Tiered risk assessment** categorizing operations as `Low`, `Medium`, or `High` threat levels
- **Autonomy-based gating** using `gate_decision` to enforce `ReadOnly`, `Supervised`, or `Full` permission models
- **Structural guards** that detect hidden subshells, background operators, and environment variable injection
- **Fail-closed defaults** that treat unrecognized commands as `Write` class and block high-risk operations unless explicitly approved

## Frequently Asked Questions

### How does OpenHuman prevent command injection attacks?

The framework prevents injection through multiple layers. The `split_unquoted_segments` function respects shell quoting rules to prevent delimiter-based injection, while `has_hidden_execution` detects subshell syntax like `$(...)` and backticks. Additionally, `is_command_allowed` rejects dangerous argument patterns such as `find -exec` and unquoted redirections, ensuring agents cannot bypass classification through command obfuscation.

### What is the difference between Supervised and Full autonomy modes?

In **Supervised** mode, agents can execute `Read` class commands automatically, but `Write`, `Network`, `Install`, and `Destructive` classes trigger user prompts. The system also enforces structural guards and allow-list validation. **Full** mode permits `Read` and `Write` commands automatically, only prompting on `Network`, `Install`, and `Destructive` operations, and skips structural guards like hidden execution detection, trusting the agent to run any command safely.

### Can I customize which commands are considered high-risk?

While the core `DESTRUCTIVE_BASES` and high-risk pattern tables are defined in the source code, the `SecurityPolicy` struct exposes configuration flags such as `block_high_risk_commands` and `require_approval_for_medium_risk`. These allow runtime adjustment of risk tolerance without modifying the underlying classification lists. Custom command classes would require modification of the `classify_segment` logic in [`policy_command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/policy_command.rs).

### What happens when a command violates the security policy?

When validation fails at any layer—whether through `gate_decision` returning `GateDecision::Block`, `is_command_allowed` detecting dangerous arguments, or `validate_command_execution` identifying high-risk operations—the system returns a `POLICY_BLOCKED_MARKER` error to the frontend. The command never reaches the execution environment, ensuring that policy violations result in safe failures rather than unauthorized actions.