openhands-sdk/penhands/sdk/security/
Core Responsibilities
The Security system has four primary responsibilities:- Risk Assessment - Capture and validate LLM-provided risk levels for actions
- Confirmation Policy - Determine when user approval is required based on risk
- Action Validation - Enforce security policies before execution
- Audit Trail - Record security decisions in event history
Architecture
Key Components
| Component | Purpose | Design |
|---|---|---|
SecurityAnalyzerBase | Abstract interface | Defines security_risk() contract |
LLMSecurityAnalyzer | Inline risk assessment | Returns LLM-provided risk from action arguments |
NoOpSecurityAnalyzer | Passthrough analyzer | Always returns UNKNOWN |
SecurityRisk | Risk enum | LOW, MEDIUM, HIGH, UNKNOWN |
ConfirmationPolicy | Decision logic | Maps risk levels to confirmation requirements |
Risk Levels
Security analyzers return one of four risk levels:Risk Level Definitions
| Level | Characteristics | Examples |
|---|---|---|
| LOW | Read-only, no state changes | File reading, directory listing, search |
| MEDIUM | Modifies user data | File editing, creating files, API calls |
| HIGH | Dangerous operations | File deletion, system commands, privilege escalation |
| UNKNOWN | Not analyzed or indeterminate | Complex commands, ambiguous operations |
Security Analyzers
LLMSecurityAnalyzer
Leverages the LLMβs inline risk assessment during action generation: Analysis Process:- Schema Enhancement: A required
security_riskparameter is added to each toolβs schema - LLM Generation: The LLM generates tool calls with
security_riskas part of the arguments - Risk Extraction: The agent extracts the
security_riskvalue from the tool call arguments - ActionEvent Creation: The security risk is stored on the
ActionEvent - Analyzer Query:
LLMSecurityAnalyzer.security_risk()returns the pre-assigned risk level - No Additional LLM Calls: Risk assessment happens inlineβno separate analysis step
- Enabled When: A
LLMSecurityAnalyzeris configured for the agent - Schema Modification: Automatically adds
security_riskfield 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 actionsConfirmation Policy
The confirmation policy determines when user approval is required. There are three policy implementations: Source:confirmation_policy.py
Policy Types
| Policy | Behavior | Use Case |
|---|---|---|
AlwaysConfirm | Requires confirmation for all actions | Maximum safety, interactive workflows |
NeverConfirm | Never requires confirmation | Fully autonomous agents, trusted environments |
ConfirmRisky | Configurable risk-based policy | Balanced 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)returnsTrueifrisk >= threshold
- Cannot be set to
confirm_unknown(default:True) - WhetherUNKNOWNrisk requires confirmation
Confirmation Rules by Policy
ConfirmRisky with threshold=HIGH (Default)
| Risk Level | confirm_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 Level | confirm_unknown=True | confirm_unknown=False |
|---|---|---|
| LOW | β Allow | β Allow |
| MEDIUM | π Require confirmation | π Require confirmation |
| HIGH | π Require confirmation | π Require confirmation |
| UNKNOWN | π Require confirmation | β Allow |
ConfirmRisky with threshold=LOW
| Risk Level | confirm_unknown=True | confirm_unknown=False |
|---|---|---|
| LOW | π Require confirmation | π Require confirmation |
| MEDIUM | π Require confirmation | π Require confirmation |
| HIGH | π Require confirmation | π Require confirmation |
| UNKNOWN | π Require confirmation | β Allow |
- Risk comparison is reflexive:
HIGH.is_riskier(HIGH)returnsTrue - UNKNOWN handling is configurable via
confirm_unknownflag - 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
- Agent Architecture - How agents use security analyzers
- Tool System - Tool annotations and metadata; includes MCP tool hints
- Security Guide - Configuring security policies

