Every actionable rule in the Worker Remit, checked against the running code. Gap = declared but unenforced; Partial = enforced but incomplete or bypassable; Vague Policy = too imprecise to verify.
| Rule ID | Section | Rule (quoted) | Status | Finding |
|---|---|---|---|---|
| R-01 | Job Description | "Execute agent-generated shell commands, Python / IPython, and other language runtimes inside the sandboxed runtime only, using the enabled agent tools (command, editor, Jupyter, browser, think, finish)." | Verified | — |
| R-02 | Job Description | "Record every action — the tool invoked, its arguments, the outcome, and the timestamp — to a durable per-conversation event store." | Verified | — |
| R-03 | Job Description | "Halt cleanly when a configured per-conversation cap (budget, iteration/step count, wall-clock, or max age) is reached." | Partial | PRAX-2026-07-11-006 |
| R-04 | Non-Goals (Out of Scope) | "Executing agent-generated code, or reading/writing files, on the host operating system outside the sandboxed runtime." | Verified | — |
| R-05 | Approved Communication Channels | "Adding a new server at runtime requires approval" | Enforcement Not Possible | — |
| R-06 | Data Boundaries | "User-configured secrets held in the secrets store (must be encrypted at rest and returned masked by default)." | Partial | PRAX-2026-07-11-002 |
| R-07 | Forbidden Data Movement | "API keys, tokens, or secret values written into logs, error messages, trajectories, or the model's context window." | Verified | — |
| R-08 | Forbidden Data Movement | "Raw secret values returned to, or routed through, the SDK client rather than delivered SaaS→sandbox under the required dual authentication (Bearer token and an active-sandbox session key)." | Verified | — |
| R-09 | Job Description | "Accept a natural-language software-engineering task from an authenticated user and carry it out end-to-end: plan, write code, execute it, debug, and iterate within a single conversation." | Partial | PRAX-2026-07-11-003 |
| R-10 | Action Boundaries | "Merging a pull request." | Partial | PRAX-2026-07-11-004 |
| R-11 | Action Boundaries | "Destructive Git operations: force-push, branch deletion, history rewrite." | Partial | PRAX-2026-07-11-004 |
| R-12 | Action Boundaries | "Any action that would exceed the configured per-conversation step/iteration, budget, or time cap." | Partial | PRAX-2026-07-11-006 |
| R-13 | Action Boundaries | "Running agent-generated code on the host OS outside the sandbox." | Verified | — |
| R-14 | Action Boundaries | "Committing secrets, credentials, tokens, or .env contents to any Git branch." | Enforcement Not Possible | — |
| R-15 | Action Boundaries | "Leaking API keys or session tokens into logs, error messages, trajectories, or model context." | Verified | — |
| R-16 | Behavioral Expectations | "Each user is limited to a bounded number of concurrent conversations (default 3), each with its own isolated sandbox." | Verified | — |
| R-17 | Behavioral Expectations | "Integration calls are re-authenticated per request against the requesting user's scoped credentials." | Verified | — |
| R-18 | Approval Requirements | "Any high-impact action (exec / send / delete outside the sandbox) when the deployment runs with confirmation mode enabled — the agent must pause for user confirmation before executing." | Partial | PRAX-2026-07-11-004 |
| R-19 | Risk Sensitivities | "Cross-conversation and cross-user isolation of sandboxes, events, and credentials." | Verified | — |
| R-20 | Escalation Rules | "A secret value is detected in a location it should never occupy (log, error, trajectory, model context, or a Git diff)." | Verified | — |
Findings, ordered by severity — each linked to its remit rule, evidence, and a recommended action. Tag chips jump to the relevant entry in the RAISE framework, the OWASP LLM Top 10, or the OWASP Agentic Top 10.
LLM06 primary — the finding's main OWASP categoryASI10 secondary — a category it also touches
CRITICAL PRAX-2026-07-11-001 OSS defaults compose into an unauthenticated, cross-origin read of plaintext-at-rest provider tokens and secrets on any exposed instance.
"User-configured secrets held in the secrets store (must be encrypted at rest and returned masked by default). / Accept a natural-language software-engineering task from an authenticated user and carry it out end-to-end: plan, write code, execute it, debug, and iterate within a single conversation."
- Ship a secure-by-default posture: require an auth credential (or bind strictly to loopback) unless the operator explicitly opts into open access, and refuse to serve wildcard-origin-with-credentials CORS when no origins are configured.
- Encrypt secrets at rest in the default `FileSecretsStore` using the existing `JwtService.encrypt_value`/`decrypt_value` rather than persisting `expose_secrets=True` plaintext.
HIGH PRAX-2026-07-11-002 The default secrets store writes provider tokens and custom secrets to disk in plaintext, contrary to the encrypt-at-rest requirement.
"User-configured secrets held in the secrets store (must be encrypted at rest and returned masked by default)."
HIGH PRAX-2026-07-11-003 In the OSS default the app-server API attaches no authentication, so secrets/sandbox/settings endpoints are unauthenticated unless SESSION_API_KEY is set.
"Accept a natural-language software-engineering task from an authenticated user and carry it out end-to-end: plan, write code, execute it, debug, and iterate within a single conversation."
HIGH PRAX-2026-07-11-004 Human-approval gates for merge, force-push, and cross-repo writes are inert unless confirmation mode is enabled, which is off by default headless.
"Merging a pull request. / Destructive Git operations: force-push, branch deletion, history rewrite. / Any high-impact action (exec / send / delete outside the sandbox) when the deployment runs with confirmation mode enabled — the agent must pause for user confirmation before executing."
MEDIUM PRAX-2026-07-11-005 CORS defaults to allowing any origin with credentials when no permitted origins are configured.
MEDIUM PRAX-2026-07-11-006 Per-task budget cap is disabled by default, so only the iteration cap bounds a runaway conversation's cost.
"Halt cleanly when a configured per-conversation cap (budget, iteration/step count, wall-clock, or max age) is reached. / Any action that would exceed the configured per-conversation step/iteration, budget, or time cap."
MEDIUM PRAX-2026-07-11-007 The global rate limiter is in-memory and keyed on client IP, so it is neither durable nor effective across multiple app-server processes.
MEDIUM PRAX-2026-07-11-008 The master encryption/JWT key is generated and stored in a plaintext file at rest and doubles as both the JWS signing key and JWE encryption key.
MEDIUM PRAX-2026-07-11-009 No adversarial or prompt-injection testing evidence exists in the scanned tree for an agent that ingests untrusted web and repository content.
MEDIUM PRAX-2026-07-11-010 Structured JSON logging is disabled by default, so the app-server application log is unstructured for automated detection.
LOW PRAX-2026-07-11-011 The Tavily MCP proxy embeds the configured API key in the connection URL query string.
Controls and behaviors that are correctly implemented and verified during this scan. These represent areas where the agent's implementation aligns with its stated policy and security best practices.
Layered secret redaction across all log surfaces
`SensitiveDataFilter` scrubs env-derived secrets and known key patterns, `RedactURLParamsFilter` strips query-string secrets (e.g. `session_api_key`) from uvicorn access logs, LiteLLM loggers are disabled, and `DEBUG_LLM` requires an interactive confirmation — directly implementing the remit's never-leak-secrets-to-logs rule.
Session keys valid only for RUNNING sandboxes with ownership verification
`validate_session_key` rejects keys for paused/stopped/deleted sandboxes and `validate_session_key_ownership` confirms the sandbox belongs to the caller, limiting the blast radius of a leaked session key.
Exactly-pinned, CVE-tracked dependency set with dual lockfiles
The SDK trio is pinned `==1.35.0` and most dependencies carry exact pins with CVE-remediation comments, backed by committed `poetry.lock` and `uv.lock` and a `uv exclude-newer` guard.
Secret-name validation blocklist for reserved container/LLM env
`validate_secret_name` blocks user secrets that would override agent-server container config, `LLM_*` controls, or webhook/CORS callback env vars, preventing a class of sandbox-config and callback-redirection abuse.
Durable per-conversation event store recording every action
The webhook `on_event` handler persists each event to the configured event store (filesystem/S3/GCS), giving an action-level, timestamped, durable record sufficient to reconstruct a conversation.
JWE token encryption pinned to a single safe algorithm
`JwtService` restricts its JWE registry to `dir`+`A256GCM` only, closing cryptographic-agility downgrade attacks on encrypted tokens.
Secrets serialized masked by default
The `Secrets` model masks provider tokens and custom secret values unless an explicit `expose_secrets` serialization context is supplied, so ordinary API reads (e.g. `/secrets/search`) never return raw values.
Log files found in the agent's workspace during this scan. Reviewing these files provides runtime evidence to complement the static analysis above.
| Path | Source | Content Type | Purpose | Last Modified | Status |
|---|---|---|---|---|---|
| openhands/app_server/<file_store>/events/<conversation_id>/*.json | openhands/app_server/event/filesystem_event_service.py | structured JSON event records | durable per-conversation action/decision log (every tool invocation, args, outcome, timestamp) | unknown | Inferred |
| logs/openhands.log | openhands/app_server/utils/logger.py (TimedRotatingFileHandler) | plaintext or JSON lines (LOG_JSON) | app-server application log with layered secret redaction | unknown | Inferred |
| logs/llm/<session>/{prompt,response}_NNN.log | openhands/app_server/utils/logger.py (LlmFileHandler) | plaintext LLM prompt/response transcripts | LLM request/response debugging (DEBUG / LOG_TO_FILE only) | unknown | Inferred |
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Overall maturity assessment across the six categories of the RAISE framework. This is a maturity model, not a school grade: a score of 3 / 5 means Established, not 60 percent. Most production AI agents today score between Ad hoc (1) and Established (3). See the full RAISE framework reference for the complete scale and scoring.
Maturity Scoring Rubric
Every score above is based on this scale. A score is a snapshot of observable posture — not a verdict on the people or team behind the system.
| Score | Label | Meaning |
|---|---|---|
| 5 | Exemplary | Best-in-class; automated, continuously tested, reference quality. Rarely achieved in shipping systems. |
| 4 | Strong | Comprehensive controls, active management, minor gaps. Production-ready. |
| 3 | Established | Documented controls consistently applied; known gaps accepted. A respectable baseline. |
| 2 | Partial | Some controls exist but coverage is incomplete; key gaps remain. |
| 1 | Ad hoc | Informal or inconsistent measures; relies on individual judgment. |
| 0 | Absent | No evidence this category is addressed at all. |