Skip to main content
The Security system evaluates agent actions for potential risks before execution. It provides pluggable security analyzers that assess action risk levels and enforce confirmation policies based on security characteristics. Source: openhands-sdk/penhands/sdk/security/

Core Responsibilities

The Security system has four primary responsibilities:
  1. Risk Assessment - Capture and validate LLM-provided risk levels for actions
  2. Confirmation Policy - Determine when user approval is required based on risk
  3. Action Validation - Enforce security policies before execution
  4. Audit Trail - Record security decisions in event history

Architecture

Key Components

ComponentPurposeDesign
SecurityAnalyzerBaseAbstract interfaceDefines security_risk() contract
LLMSecurityAnalyzerInline risk assessmentReturns LLM-provided risk from action arguments
NoOpSecurityAnalyzerPassthrough analyzerAlways returns UNKNOWN
SecurityRiskRisk enumLOW, MEDIUM, HIGH, UNKNOWN
ConfirmationPolicyDecision logicMaps risk levels to confirmation requirements

Risk Levels

Security analyzers return one of four risk levels:

Risk Level Definitions

LevelCharacteristicsExamples
LOWRead-only, no state changesFile reading, directory listing, search
MEDIUMModifies user dataFile editing, creating files, API calls
HIGHDangerous operationsFile deletion, system commands, privilege escalation
UNKNOWNNot analyzed or indeterminateComplex commands, ambiguous operations

Security Analyzers

LLMSecurityAnalyzer

Leverages the LLM’s inline risk assessment during action generation: Analysis Process:
  1. Schema Enhancement: A required security_risk parameter is added to each tool’s schema
  2. LLM Generation: The LLM generates tool calls with security_risk as part of the arguments
  3. Risk Extraction: The agent extracts the security_risk value from the tool call arguments
  4. ActionEvent Creation: The security risk is stored on the ActionEvent
  5. Analyzer Query: LLMSecurityAnalyzer.security_risk() returns the pre-assigned risk level
  6. No Additional LLM Calls: Risk assessment happens inlineβ€”no separate analysis step
Example Tool Call:
{
  "name": "execute_bash",
  "arguments": {
    "command": "rm -rf /tmp/cache",
    "security_risk": "HIGH"
  }
}
The LLM reasons about risk in context when generating the action, eliminating the need for a separate security analysis call. Configuration:
  • Enabled When: A LLMSecurityAnalyzer is configured for the agent
  • Schema Modification: Automatically adds security_risk field to non-read-only tools
  • Zero Overhead: No additional LLM calls or latency beyond normal action generation

NoOpSecurityAnalyzer

Passthrough analyzer that skips analysis: Use Case: Development, trusted environments, or when confirmation mode handles all actions

Confirmation Policy

The confirmation policy determines when user approval is required. There are three policy implementations: Source: confirmation_policy.py

Policy Types

PolicyBehaviorUse Case
AlwaysConfirmRequires confirmation for all actionsMaximum safety, interactive workflows
NeverConfirmNever requires confirmationFully autonomous agents, trusted environments
ConfirmRiskyConfigurable risk-based policyBalanced approach, production use

ConfirmRisky (Default Policy)

The most flexible policy with configurable thresholds: Configuration:
  • threshold (default: HIGH) - Risk level at or above which confirmation is required
    • Cannot be set to UNKNOWN
    • Uses reflexive comparison: risk.is_riskier(threshold) returns True if risk >= threshold
  • confirm_unknown (default: True) - Whether UNKNOWN risk requires confirmation

Confirmation Rules by Policy

ConfirmRisky with threshold=HIGH (Default)

Risk Levelconfirm_unknown=True (default)confirm_unknown=False
LOWβœ… Allowβœ… Allow
MEDIUMβœ… Allowβœ… Allow
HIGHπŸ”’ Require confirmationπŸ”’ Require confirmation
UNKNOWNπŸ”’ Require confirmationβœ… Allow

ConfirmRisky with threshold=MEDIUM

Risk Levelconfirm_unknown=Trueconfirm_unknown=False
LOWβœ… Allowβœ… Allow
MEDIUMπŸ”’ Require confirmationπŸ”’ Require confirmation
HIGHπŸ”’ Require confirmationπŸ”’ Require confirmation
UNKNOWNπŸ”’ Require confirmationβœ… Allow

ConfirmRisky with threshold=LOW

Risk Levelconfirm_unknown=Trueconfirm_unknown=False
LOWπŸ”’ Require confirmationπŸ”’ Require confirmation
MEDIUMπŸ”’ Require confirmationπŸ”’ Require confirmation
HIGHπŸ”’ Require confirmationπŸ”’ Require confirmation
UNKNOWNπŸ”’ Require confirmationβœ… Allow
Key Rules:
  • Risk comparison is reflexive: HIGH.is_riskier(HIGH) returns True
  • UNKNOWN handling is configurable via confirm_unknown flag
  • Threshold cannot be UNKNOWN - validated at policy creation time

Component Relationships

Relationship Characteristics:
  • Agent β†’ Security: Validates actions before execution
  • Security β†’ Tools: Examines tool characteristics (annotations)
  • Security β†’ MCP: Uses MCP hints for risk assessment
  • Conversation β†’ Agent: Pauses for user confirmation when required
  • Optional Component: Security analyzer can be disabled for trusted environments

See Also