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 viaApprovalGate::process. - Risk tiers defined in
types.rsclassify 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 viaopenhuman.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.dbenables "Approve Once" semantics across session lifetimes, reducing friction for trusted workflows. - Audit trails captured in
store.rsprovide tamper-evident logs accessible viaopenhuman.approval_list_recent_decisionsfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →