How the Approval Gate in OpenHuman Prevents Unauthorized Agent Operations While Allowing Background Tasks

The OpenHuman approval gate intercepts every tool invocation in the request-handling pipeline to enforce risk-based authorization, parking interactive sessions for user consent while automatically approving background tasks marked with is_background = true.

The tinyhumansai/openhuman repository implements a security-focused execution model where agent-generated operations cannot invoke sensitive tools without explicit permission. By embedding the approval gate in OpenHuman directly into the core dispatch pipeline through src/openhuman/security/approval/gate.rs, the system guarantees least-privilege execution for user-facing interactions without disrupting automated cron jobs or autonomous agent workflows.

Core Architecture of the Approval System

The approval mechanism centers on src/openhuman/security/approval/gate.rs, where the ApprovalGate struct evaluates every tool call against session context and risk classification before execution proceeds.

Risk Tier Classification

Every tool definition registers a risk tier (low, medium, or high) in src/openhuman/security/approval/types.rs. The gate uses this classification to determine whether a specific operation requires human oversight based on the session's configured approval mode.

Execution Context Detection

The gate distinguishes between foreground (interactive) and background execution contexts through the is_background boolean flag. This distinction resides in the core logic of gate.rs, where the should_prompt method checks this flag to decide whether to initiate the approval workflow or permit immediate execution.

Interactive Session Protection

When a user-facing chat or interactive turn triggers a tool call, the gate treats the operation as foreground execution and applies the full consent protocol.

Parking and Pending Requests

If the session's approval mode is required for the tool's risk tier, ApprovalGate::process parks the turn and inserts a pending request into the store at src/openhuman/security/approval/store.rs. The UI then queries these pending items via the JSON-RPC endpoint openhuman.approval_list_pending, defined in src/openhuman/security/approval/schemas.rs.

User Decisions via RPC

Users resolve parked requests through the openhuman.approval_decide RPC endpoint, selecting from three options:

  • Approve: Grants permanent permission for this tool in the current session
  • Deny: Rejects the operation permanently
  • ApproveOnce: Allows the single operation and requires confirmation for subsequent calls
// Query pending approvals from the frontend
GET /rpc/openhuman.approval_list_pending
// Submit a decision for a specific audit ID
POST /rpc/openhuman.approval_decide
{
  "auditId": "a1b2c3",
  "decision": "ApproveOnce"
}

Background Task Automation

Operations flagged as background tasks bypass the interactive prompt to support autonomous agents and scheduled jobs.

The Background Bypass Mechanism

In src/openhuman/security/approval/gate.rs, the should_prompt method returns false immediately when ctx.is_background equals true. This allows the gate to treat these turns as trusted, executing the tool without user intervention.

// Create a background turn that skips approval gates
let turn = harness
    .turn("Refresh my feed.")
    .session(&session_id)
    .background(true)  // Marks as background task
    .send()
    .await?;

Maintaining Security Boundaries

Background bypass applies only to turns explicitly created with the background flag. Standard interactive sessions cannot accidentally trigger this bypass, ensuring that user-facing agents cannot mask malicious operations as background tasks.

Decision Persistence and Audit Infrastructure

The gate maintains a tamper-evident record of all decisions to support "Approve Once" semantics and compliance requirements.

SQLite Storage Layer

Decisions persist in approval/approval.db via functions in src/openhuman/security/approval/store.rs. When approval_store::decide records a choice, subsequent calls from the same session automatically inherit the outcome, preventing redundant prompting for approved tools.

Audit Trail RPC

Administrators and developers can query the complete history of pending requests, decisions, and execution outcomes through openhuman.approval_list_recent_decisions. This creates a comprehensive log for debugging agent behavior and verifying security policy adherence.

Integration with the Tool Dispatch Pipeline

The approval gate integrates directly into the execution pathway through the ToolHook trait implementation in src/core/dispatch.rs.

The Process Hook

All tool invocations flow through ApprovalGate::process, which acts as a mandatory checkpoint. This integration guarantees that no tool can execute without the gate's consent check unless the caller explicitly marks the turn as background. The dispatcher registration ensures the gate evaluates every operation, regardless of whether it originates from a chat interface, API call, or internal agent loop.

// Manual check pattern for custom tool implementations
if approval_gate.should_prompt(&ctx, tool_risk) {
    approval_gate.park(&ctx, tool_risk).await?;
} else {
    tool.run().await?;
}

Summary

  • The approval gate in OpenHuman sits between tool parsing and execution in src/openhuman/security/approval/gate.rs, enforcing mandatory authorization checks via ApprovalGate::process.
  • Risk tiers defined in types.rs classify tools as low, medium, or high sensitivity to determine authorization requirements.
  • Interactive sessions trigger the parking mechanism, storing pending requests in the SQLite-backed store (store.rs) and awaiting user decisions via openhuman.approval_decide.
  • Background tasks skip user prompts when is_background = true, allowing autonomous agents to execute without interruption while maintaining security boundaries for foreground operations.
  • Decision persistence in approval/approval.db enables "Approve Once" semantics across session lifetimes, reducing friction for trusted workflows.
  • Audit trails captured in store.rs provide tamper-evident logs accessible via openhuman.approval_list_recent_decisions for compliance and debugging.

Frequently Asked Questions

Can background tasks be forced to require manual approval?

No. By design, background tasks marked with is_background = true bypass the interactive prompt entirely as implemented in gate.rs. If you need oversight for automated workflows, run them as foreground sessions with elevated approval modes rather than background tasks.

How does the system handle sessions where the user selects "Approve Once"?

When a user submits "decision": "ApproveOnce" via the openhuman.approval_decide RPC endpoint, approval_store::decide in src/openhuman/security/approval/store.rs records this choice in the SQLite database. The gate permits the immediate operation but removes the persistent grant, requiring future re-authorization for identical tool calls.

Where is the approval state stored between application restarts?

All pending requests, decisions, and audit logs persist in approval/approval.db using the SQLite backend managed by src/openhuman/security/approval/store.rs. This ensures that approval states survive process restarts and can be reconstructed when the OpenHuman core restarts.

What prevents a malicious agent from marking all turns as background to bypass approval?

The is_background flag requires explicit construction through the turn builder API (.background(true)), which is typically restricted to authenticated system contexts or specific automation harnesses. Interactive user sessions cannot arbitrarily set this flag without code-level access to the session builder, maintaining the security boundary between foreground and background execution contexts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →