# Defense-in-depth score: elizaOS

**Repo:** https://github.com/elizaOS/eliza · **Commit:** `aa4f2b043b7af36517ce335319c99c68db449aa8` · **Reviewed:** 2026-10-05
**What it is:** TypeScript framework and app stack for autonomous AI agents: core runtime, standalone agent host, desktop/web/mobile app and first-party plugins.
**Category:** Agent Frameworks
**Scored configuration:** Standalone agent host run from source on a desktop OS (bun run start), default config: desktop core plugins including coding tools, browser and scheduling, runtime mode unset (local-yolo), API on loopback.
**Agent surface (default):** code execution yes · filesystem write yes · network egress yes · external credentials yes · persistent memory yes · untrusted input yes · third party extensions yes · sub agents opt-in · external communication yes

## Score: 2.8 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L1 | L1 | L0 | L0 | 0.15 | none | **0.15** | High |
| C2 | Approval gates | L2 | L1 | L1 | L1 | 0.33 | G2 | **0.25** | High |
| C3 | Tool & action scoping | L1 | L2 | L1 | L0 | 0.28 | none | **0.28** | High |
| C4 | Code-execution isolation | L2 | L1 | L0 | L3 | 0.38 | G1 | **0.38** (alt) | High |
| C5 | Untrusted input blast radius | L1 | L1 | L2 | L0 | 0.25 | C5-WORSTCASE | **0.25** | High |
| C6 | Memory, context & configuration integrity | L0 | L0 | L0 | L1 | 0.05 | C6-REPOCONFIG | **0.05** | High |
| C7 | Third-party extensions | L1 | L1 | L0 | L0 | 0.15 | none | **0.15** | High |
| C8 | Secrets & sensitive-data protection | L2 | L2 | L2 | L1 | 0.45 | none | **0.45** | High |
| C9 | Audit & traceability | L2 | L2 | L1 | L1 | 0.40 | none | **0.40** | Medium |
| C10 | Limits & kill switch | L2 | L2 | L2 | L1 | 0.45 | none | **0.45** | High |


elizaOS ships a lot of careful security engineering (per-requester role checks, an SSRF-guarded web fetch, a vault for connector tokens, a confirm-code gate for destructive shell commands), but the default desktop agent runs any other shell command directly on your machine as you, with your model and connector keys in its environment. A web page or document that hijacks the agent can read your files and send them out, or make irreversible changes, without asking. Instruction files and startup hooks from the project folder load without a trust prompt. Turn on the container sandbox mode and set workspace roots before pointing it at anything you care about.

## Critical gaps
- Shell commands run as the logged-in user and inherit the agent's provider and connector keys, so a hijacked owner session reaches the user's whole account. (ASI03; C1). Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10)
- The shell confirmation for destructive commands can be switched off at runtime without an operator decision. (ASI09, ASI02; C2). Evidence: [plugins/plugin-coding-tools/src/actions/bash.ts:1932-1934](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1932-L1934)
- Shell commands run directly on the host by default; the container sandbox is opt-in. (ASI05; C4). Evidence: [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144); [plugins/plugin-coding-tools/src/lib/run-shell.ts:746-752](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L746-L752)
- If content the agent reads hijacks it, it can leak files and keys and take irreversible actions through the shell with no human involved. (ASI01; C5). Evidence: [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85); [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216)
- A project folder used as the workspace can add startup hooks and instruction files that load without a trust decision. (ASI06, ASI04; C6). Evidence: [packages/agent/src/shared/workspace-resolution.ts:137-146](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/shared/workspace-resolution.ts#L137-L146); [packages/agent/src/hooks/discovery.ts:172-208](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/discovery.ts#L172-L208); [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31)
- Plugins, drop-ins and hooks run inside the agent process with all of its credentials. (ASI04; C7). Evidence: [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31); [packages/agent/src/runtime/plugin-resolver.ts:2709-2721](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/plugin-resolver.ts#L2709-L2721)

## Criterion details

### C1 Identity & least privilege: 0.15 (high confidence)

Actions are checked against the role of the person who asked (owner, admin, user, guest) on every execution path, and a failed role lookup refuses instead of guessing. But the authority behind those actions is the operator's own: shell commands run as the local OS user and inherit the agent's process environment, where configured model and connector keys are placed, and only code-injection variables are stripped. The file tools refuse a short list of credential folders, while the shell does not.

- **S L1:** Authority is the operator's OS account plus the keys in the process environment; the only narrowing is a file-tool blocklist of credential folders and role checks on who may call powerful actions. Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216); [packages/core/src/security/spawn-env-policy.ts:18-27](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/security/spawn-env-policy.ts#L18-L27); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10); [packages/agent/src/runtime/eliza.ts:1772-1801](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/eliza.ts#L1772-L1801); [plugins/plugin-coding-tools/src/services/sandbox-service.ts:1-7](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L1-L7) (verified)
  - *To reach the next level:* No dedicated or scoped identity: shell children receive model and connector keys, and nothing narrows the OS account.
- **C L1:** The role gate covers every action path, but every shell subprocess inherits the full process environment minus injection variables. Evidence: [packages/core/src/runtime/action-gate.ts:81-89](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/action-gate.ts#L81-L89); [packages/core/src/runtime/action-gate.ts:125-131](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/action-gate.ts#L125-L131); [plugins/plugin-coding-tools/src/lib/run-shell.ts:607-613](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L607-L613) (verified)
  - *To reach the next level:* Subprocesses and plugins use ambient credentials; L2 needs all built-in tools on a scoped identity.
- **D L0:** The default desktop install loads the shell tool and runs it with the owner's full OS privileges. Evidence: [packages/agent/src/runtime/core-plugins.ts:73-81](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/core-plugins.ts#L73-L81); [plugins/plugin-coding-tools/src/actions/bash.ts:1200-1204](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1200-L1204); [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144) (verified)
  - *To reach the next level:* Least privilege needs manual hardening (sandbox mode, workspace roots); L1 needs a narrower default.
- **B L0:** A hijacked owner session reaches the user's whole account: home directory, any credentials the OS user holds, and the configured provider and connector keys. Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:607-613](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L607-L613); [plugins/plugin-coding-tools/src/services/sandbox-service.ts:47-48](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L47-L48); [plugins/plugin-coding-tools/README.md:6-8](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/README.md#L6-L8) (verified)
  - *To reach the next level:* L1 needs the agent's reach limited below the full user account.
- **Cap:** none

### C2 Approval gates: 0.25 (high confidence)

Shell commands that a built-in classifier flags as destructive (recursive deletes, disk wipes, dropping database objects) stop and ask the user to reply with a one-time code, and that approval is bound to the exact command, folder, requester and conversation. Everything else runs without asking: other shell commands, file writes and edits, web requests and browser actions. The confirmation can be turned off at runtime without an operator decision, and there is no undo for file or shell changes.

- **S L2:** Per-command human confirmation for classifier-flagged shell commands, bound to the exact command digest, folder, requester and a later message; the approver sees what the model relays. Evidence: [plugins/plugin-coding-tools/src/actions/bash.ts:1935-1940](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1935-L1940); [plugins/plugin-coding-tools/src/lib/destructive-confirmation.ts:124-145](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/destructive-confirmation.ts#L124-L145); [plugins/plugin-coding-tools/src/lib/destructive-gate.ts:1-6](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/destructive-gate.ts#L1-L6) (verified)
  - *To reach the next level:* The approver doesn't see a host-rendered view of the exact call, and only one risk tier exists; L3 needs the exact call shown with tiered gating.
- **C L1:** Only commands on the destructive classifier's list are gated; other shell commands, WRITE/EDIT, WEB_FETCH and browser actions run unapproved. Evidence: [plugins/plugin-coding-tools/src/actions/bash.ts:1935-1940](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1935-L1940); [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85); searched `rg -n -S 'rollback|undo'` in `plugins/plugin-coding-tools/src/actions/write.ts plugins/plugin-coding-tools/src/actions/edit.ts` → 0 hits (no undo or checkpoint for file writes) (verified)
  - *To reach the next level:* Consequential tools other than flagged shell commands skip the gate; L2 needs every built-in mutating tool gated.
- **D L1:** The confirmation is on by default, but it can be switched off at runtime without an operator decision. Evidence: [plugins/plugin-coding-tools/src/actions/bash.ts:1932-1934](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1932-L1934) (verified)
  - *To reach the next level:* L2 needs only the operator to be able to disable it.
- **B L1:** Shell and file changes have no checkpoint or rollback; pushes, network sends and overwrites are irreversible. Evidence: searched `rg -n -S 'rollback|undo'` in `plugins/plugin-coding-tools/src/actions/write.ts plugins/plugin-coding-tools/src/actions/edit.ts` → 0 hits (no undo or checkpoint for file writes); [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85) (verified)
  - *To reach the next level:* No checkpoints or undo for the workspace; L2 needs the common case reversible.
- **Cap:** G2: The model can switch the shell confirmation off at runtime without an operator decision.

### C3 Tool & action scoping: 0.28 (high confidence)

The file tools resolve symlinks and refuse a list of private and system locations, and web fetches go through a guard that pins DNS, re-checks redirects and blocks private network addresses. But the file tools are otherwise allowed anywhere on disk unless the operator sets workspace roots, and the shell tool takes any command string. Shell, file write and web tools are all enabled by default; shell can be switched off as a whole.

- **S L1:** File paths are realpath-resolved against a denylist and web URLs pass an SSRF guard, but the default tool set includes a raw shell command string. Evidence: [plugins/plugin-coding-tools/src/services/sandbox-service.ts:177-204](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L177-L204); [plugins/plugin-coding-tools/src/services/sandbox-service.ts:47-48](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L47-L48); [plugins/plugin-coding-tools/src/lib/web-http.ts:1-6](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/web-http.ts#L1-L6); [plugins/plugin-coding-tools/src/actions/bash.ts:1200-1204](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1200-L1204) (verified)
  - *To reach the next level:* Raw shell passthrough and a path denylist rather than an allowlist; L2 needs typed validation without general passthrough.
- **C L2:** Built-in file and web tools validate through shared services; the shell validates only its working directory, and plugin tools have no shared validation layer. Evidence: [plugins/plugin-coding-tools/src/services/sandbox-service.ts:177-204](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L177-L204); [plugins/plugin-coding-tools/src/lib/web-http.ts:1-6](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/web-http.ts#L1-L6) (verified)
  - *To reach the next level:* No shared validation layer for extension tools; L3 needs every built-in tool validated and extensions wrapped.
- **D L1:** Write, shell and network tools are on by default; the shell surface can be disabled as a feature. Evidence: [packages/agent/src/runtime/core-plugins.ts:73-81](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/core-plugins.ts#L73-L81); [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85); [packages/agent/src/runtime/plugin-collector.ts:849-853](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/plugin-collector.ts#L849-L853) (verified)
  - *To reach the next level:* No tool groups or read-only default; L2 needs selectable groups.
- **B L0:** The shell is a general-purpose tool against the whole machine as the OS user. Evidence: [plugins/plugin-coding-tools/README.md:6-8](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/README.md#L6-L8); [plugins/plugin-coding-tools/src/lib/run-shell.ts:746-752](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L746-L752) (verified)
  - *To reach the next level:* L1 needs the general tools limited below the whole machine.
- **Cap:** none

### C4 Code-execution isolation: 0.38 (high confidence)

By default the shell tool runs commands directly on the host with bash as the logged-in user, because the runtime mode defaults to the unsandboxed local mode. An opt-in safe mode routes commands into a Docker or Apple container that runs as a non-root user with all capabilities dropped, no network and memory and process limits, and it refuses to run rather than fall back to the host when no sandbox is available. That container still mounts the workspace read-write, and in-process hooks and plugins never pass through it.

- **default configuration** (default; raw 0.00 → 0.00)
  - **S L0:** Default mode is local-yolo: SHELL spawns /bin/bash -c on the host as the OS user. Evidence: [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144); [plugins/plugin-coding-tools/src/lib/run-shell.ts:746-752](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L746-L752); [plugins/plugin-coding-tools/src/lib/run-shell.ts:607-613](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L607-L613) (verified)
    - *To reach the next level:* No isolation primitive by default; L1 needs at least a filtering layer around execution.
  - **C L0:** No execution path is sandboxed in the default mode. Evidence: [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144); [plugins/plugin-coding-tools/src/lib/run-shell.ts:607-613](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L607-L613) (verified)
    - *To reach the next level:* L1 needs the main exec tool sandboxed.
  - **D L0:** Sandboxing requires setting the runtime mode to local-safe; the resolver defaults to local-yolo. Evidence: [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144) (verified)
    - *To reach the next level:* Off by default; L1+ needs it on.
  - **B L0:** Commands run as the user with the home directory, network and inherited provider and connector keys. Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10); [plugins/plugin-coding-tools/src/services/sandbox-service.ts:47-48](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L47-L48) (verified)
    - *To reach the next level:* Host-equivalent reach; L1 needs credentials kept out of the execution environment.
- **opt-in local-safe container sandbox (ELIZA_RUNTIME_MODE=local-safe)** (alt; raw 0.38, cap G1 → 0.38) ← counted
  - **S L2:** Docker/Apple container running as 1000:1000 with all capabilities dropped, no network and resource limits; no no-new-privileges or read-only root by default. Evidence: [packages/agent/src/services/sandbox-manager.ts:139-152](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/sandbox-manager.ts#L139-L152); [packages/agent/src/services/sandbox-engine.ts:412-426](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/sandbox-engine.ts#L412-L426) (verified)
    - *To reach the next level:* No no-new-privileges, seccomp profile or read-only root in the default sandbox config; L3 needs a hardened profile.
  - **C L1:** SHELL foreground runs go through the sandbox and fail closed when it is unavailable; hooks and plugins still run in-process on the host. Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:788-794](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L788-L794); [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31) (verified)
    - *To reach the next level:* Hooks, plugins and other spawn paths are outside the sandbox; L2 needs most paths sandboxed.
  - **D L0:** Opt-in through the runtime mode setting. Evidence: [packages/host/src/config/runtime-mode.ts:124-144](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/host/src/config/runtime-mode.ts#L124-L144) (verified)
    - *To reach the next level:* Off by default; L1+ needs it on.
  - **B L3:** Only the workspace is mounted, the container env is empty by default, network is none and CPU, memory and PID limits apply. Evidence: [packages/agent/src/services/sandbox-manager.ts:139-152](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/sandbox-manager.ts#L139-L152); [packages/agent/src/services/sandbox-manager.ts:220-236](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/sandbox-manager.ts#L220-L236) (verified)
    - *To reach the next level:* The container is long-lived rather than ephemeral; L4 needs per-run disposal.
- **Cap:** G1: Opt-in mechanism: off in the scored default configuration.

### C5 Untrusted input blast radius: 0.25 (high confidence)

Some untrusted content, such as email and webhook payloads, is wrapped in markers with a warning and checked against injection patterns, but matches are only logged. The coding tools' web fetch and search results are not wrapped, and nothing limits what the agent can do after reading untrusted content. In one default session the agent can read web pages, reach the user's files and keys, and send data out or change things through the shell without a human, so a successful injection can both leak data and take irreversible actions.

- **S L1:** Delimiter wrapping and pattern detection for some external content; detection only logs. Evidence: [packages/core/src/security/external-content.ts:1-4](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/security/external-content.ts#L1-L4); [packages/core/src/security/external-content.ts:14-25](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/security/external-content.ts#L14-L25); searched `rg -n -S 'taint'` in `packages/core/src/runtime plugins/plugin-assistant/src/runtime` → 1 hits (the single hit is the word 'uncertainty'; no taint or provenance tracking gates tools after untrusted input) (verified)
  - *To reach the next level:* No capability is restricted after untrusted input; L2 needs approval for dangerous capabilities once untrusted content is read.
- **C L1:** Wrapping is applied on email/webhook and assistant paths, not to WEB_FETCH or WEB_SEARCH results. Evidence: searched `rg -n -S 'wrapExternal|UNTRUSTED|untrusted'` in `plugins/plugin-coding-tools/src/actions` → 1 hits (the single hit is a code comment about parsing command output; WEB_FETCH/WEB_SEARCH results are not wrapped or flagged); [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85) (verified)
  - *To reach the next level:* Web, file and tool results aren't distinguished; L2 needs most sources covered.
- **D L2:** Where wired, the wrapper is always on; it has no configuration switch. Evidence: [packages/core/src/security/external-content.ts:1-4](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/security/external-content.ts#L1-L4) (verified)
  - *To reach the next level:* Bounded by the detection-only mechanism; a structural limit would be needed for more.
- **B L0:** A hijacked session can read user files and keys, send them out with the shell or web fetch, and push, overwrite or delete outside the classifier's list, all unattended. Evidence: [plugins/plugin-coding-tools/src/index.ts:76-85](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/index.ts#L76-L85); [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216); [plugins/plugin-coding-tools/src/actions/bash.ts:1935-1940](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L1935-L1940) (verified)
  - *To reach the next level:* L1 needs either exfiltration or irreversible actions to require a human.
- **Cap:** C5-WORSTCASE: Worst case (B L0): a hijacked agent can leak data and take irreversible actions unattended.

### C6 Memory, context & configuration integrity: 0.05 (high confidence)

The agent loads instruction files such as AGENTS.md, USER.md and MEMORY.md from its workspace into every conversation, and its own template tells it to write facts and reflections there. When the agent is started in a project folder, that folder becomes the workspace, so the project's instruction files load silently, and startup hooks found in the workspace are loaded and run inside the agent process without a trust decision. These files are shared across all conversations, are not tagged by source and can steer tool use.

- **S L0:** The model writes persistent memory files that are re-injected as context, and workspace files can add startup hooks with no prompt. Evidence: [packages/agent/src/providers/workspace.ts:115-122](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/providers/workspace.ts#L115-L122); [packages/agent/src/providers/workspace-provider.ts:1-8](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/providers/workspace-provider.ts#L1-L8); [packages/agent/src/hooks/discovery.ts:172-208](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/discovery.ts#L172-L208); [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31) (verified)
  - *To reach the next level:* No validation or approval for memory writes and no trust decision for workspace hooks; L1 needs at least logged writes and no silent hook loading.
- **C L0:** Neither the memory files, the auto-loaded instruction files nor the workspace hooks are controlled. Evidence: [packages/agent/src/providers/workspace-provider.ts:1-8](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/providers/workspace-provider.ts#L1-L8); [packages/agent/src/runtime/eliza.ts:5846-5850](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/eliza.ts#L5846-L5850); searched `rg -n -S 'trust'` in `packages/agent/src/hooks` → 0 hits (no trust decision before workspace hooks load) (verified)
  - *To reach the next level:* L1 needs at least one store controlled.
- **D L0:** Workspace files come from one directory per agent and are injected for every conversation regardless of who is talking. Evidence: [packages/agent/src/providers/workspace-provider.ts:72](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/providers/workspace-provider.ts#L72); [packages/agent/src/runtime/eliza.ts:4229-4230](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/eliza.ts#L4229-L4230) (verified)
  - *To reach the next level:* No per-user namespace for workspace memory; L1 needs per-user isolation.
- **B L1:** Poisoned files persist across the user's sessions and can trigger tool use, including the shell. Evidence: [packages/agent/src/providers/workspace.ts:115-122](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/providers/workspace.ts#L115-L122); [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31) (verified)
  - *To reach the next level:* L2 needs persisted content to influence only text or gated actions.
- **Cap:** C6-REPOCONFIG: A project folder used as the workspace can supply startup hooks and instruction files that load without an explicit user trust decision.

### C7 Third-party extensions: 0.15 (high confidence)

Plugins can be installed from the elizaOS registry, including by the agent itself through an owner-only action, using the package manager with install scripts disabled; an approval-bound path can pin an exact version, but the default install takes the registry's current version and can fall back to a git clone. Plugins, drop-in plugins from the state folder and workspace hooks all run inside the agent process with its full environment, and none of them is checked against a hash or signature.

- **S L1:** Registry-restricted installs with install scripts disabled, but versions float unless an approval binding is supplied, with a git fallback; hooks and drop-ins are unverified. Evidence: [packages/agent/src/actions/plugin.ts:201-210](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/actions/plugin.ts#L201-L210); [packages/agent/src/services/plugin-installer.ts:902-917](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/plugin-installer.ts#L902-L917); [packages/agent/src/services/plugin-installer.ts:15-19](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/plugin-installer.ts#L15-L19); searched `rg -n -S 'sha256|integrity|signature'` in `packages/agent/src/hooks` → 1 hits (the single hit is a type comment ('Handler function signature'); hooks are not verified) (verified)
  - *To reach the next level:* Versions aren't pinned by default; L2 needs pinned versions.
- **C L1:** Only registry installs have any provenance handling; drop-in plugins and hooks have none. Evidence: [packages/agent/src/runtime/plugin-resolver.ts:2709-2721](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/plugin-resolver.ts#L2709-L2721); [packages/agent/src/hooks/discovery.ts:172-208](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/discovery.ts#L172-L208) (verified)
  - *To reach the next level:* L2 needs most extension types verified.
- **D L0:** Workspace hooks and drop-in plugins load automatically, and the agent can install registry plugins itself. Evidence: [packages/agent/src/hooks/loader.ts:80-82](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L80-L82); [packages/agent/src/runtime/plugin-resolver.ts:2709-2721](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/plugin-resolver.ts#L2709-L2721); [packages/agent/src/actions/plugin.ts:877-879](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/actions/plugin.ts#L877-L879) (verified)
  - *To reach the next level:* L1 needs an install step with consent; files in the workspace must not add extensions silently.
- **B L0:** Extensions run in-process with all the agent's credentials and environment. Evidence: [packages/agent/src/hooks/loader.ts:28-31](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/hooks/loader.ts#L28-L31); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10) (verified)
  - *To reach the next level:* L1 needs at least a separate process.
- **Cap:** none

### C8 Secrets & sensitive-data protection: 0.45 (high confidence)

Connector OAuth tokens go into an encrypted vault keyed from the OS keychain, the main config file is written with owner-only permissions, and shell output and logs pass through secret redaction. Model provider and connector keys are still copied into the process environment, so every shell command the agent runs inherits them, and the session-level secret substitution that keeps secrets out of model context is off by default. No third-party telemetry was found; boot telemetry stays on local disk.

- **S L2:** Vault encryption for connector credentials, 0600 config files, and redaction of shell output and logs; provider keys live in plaintext config and the process environment. Evidence: [packages/agent/src/services/connector-credential-store.ts:12-24](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/services/connector-credential-store.ts#L12-L24); [packages/agent/src/config/config.ts:597](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L597); [plugins/plugin-coding-tools/src/shell/redaction.ts:13-22](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/shell/redaction.ts#L13-L22); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10) (verified)
  - *To reach the next level:* Provider keys aren't in the keychain and secret substitution before model-bound messages is off; L3 needs both.
- **C L2:** Logs and tool output are redacted; subprocess environments and model-bound messages are not protected by default. Evidence: [plugins/plugin-coding-tools/src/shell/redaction.ts:13-22](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/shell/redaction.ts#L13-L22); [plugins/plugin-coding-tools/src/lib/run-shell.ts:215-216](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L215-L216); [packages/core/src/runtime.ts:818-824](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime.ts#L818-L824) (verified)
  - *To reach the next level:* Subprocess environments and model-bound messages are uncovered; L3 needs all listed paths.
- **D L2:** No third-party telemetry; secret swap is opt-in. Evidence: searched `rg -n -S 'sentry|posthog|mixpanel|amplitude'` in `packages/agent/src packages/core/src packages/host/src` → 17 hits (all hits are unrelated identifiers (packageNodeModulesEntryPath, ownsEntry, audio amplitude); no third-party telemetry SDK); [packages/core/src/runtime.ts:818-824](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime.ts#L818-L824) (verified)
  - *To reach the next level:* Redaction of model-bound content is opt-in; L3 needs redaction always on.
- **B L1:** Long-lived model provider keys (and any configured connector tokens) are reachable by every shell subprocess; they are moderately scoped rather than cloud-admin credentials. Evidence: [plugins/plugin-coding-tools/src/lib/run-shell.ts:607-613](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/lib/run-shell.ts#L607-L613); [packages/agent/src/config/config.ts:1-10](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/config/config.ts#L1-L10) (verified)
  - *To reach the next level:* Keys are long-lived and shared with every subprocess; L2 needs scoped keys kept out of subprocess environments.
- **Cap:** none

### C9 Audit & traceability: 0.40 (medium confidence)

When enabled, the trajectory recorder stores each model call and its tool calls with arguments in the local database, and a separate audit feed records sandbox and policy events. Trajectory recording is on in development runs but off by default in production builds unless the operator opts in. Records live in the agent's own state, which its file and shell tools can reach, and actions do not wait for their record to be written; tools run by external coding agents are not captured.

- **S L2:** Structured per-call records of tool name and arguments in trajectories. Evidence: [packages/core/src/runtime/trajectory-recorder.ts:39-58](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/trajectory-recorder.ts#L39-L58); [packages/agent/src/security/audit-log.ts:1-6](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/security/audit-log.ts#L1-L6) (verified)
  - *To reach the next level:* No actor or approver attribution on records; L3 needs principal and approver fields.
- **C L2:** Built-in tool calls are recorded through the planner; external sub-agent CLIs and in-process hooks are not. Evidence: [packages/core/src/runtime/trajectory-recorder.ts:39-58](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/trajectory-recorder.ts#L39-L58); [packages/agent/src/runtime/plugin-collector.ts:77-110](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/plugin-collector.ts#L77-L110) (verified)
  - *To reach the next level:* Extensions, hooks and approvals aren't recorded; L3 needs all tool calls and approval decisions.
- **D L1:** On in development, off when NODE_ENV=production; stored in the agent's state where its own tools can write. Evidence: [packages/core/src/runtime/trajectory-gate.ts:61-69](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/trajectory-gate.ts#L61-L69); [plugins/plugin-coding-tools/src/services/sandbox-service.ts:47-48](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/services/sandbox-service.ts#L47-L48) (verified)
  - *To reach the next level:* Off in production builds and editable by the agent; L2 needs it on by default outside the agent's reach.
- **B L1:** Writes throw when storage is unavailable, but actions don't depend on the record being written. Evidence: [packages/agent/src/runtime/trajectory-steps-writer.ts:1-8](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/trajectory-steps-writer.ts#L1-L8) (inferred)
  - *To reach the next level:* Records aren't durable per action before execution; L2 needs per-action flush with surfaced errors.
- **Cap:** none

### C10 Limits & kill switch: 0.45 (high confidence)

Each turn has a 1.5 million prompt-token budget and a breaker that stops repeated identical tool calls, and shell commands time out after two minutes by default (ten at most). There is no cap on the number of tool calls, and background shell sessions and the always-loaded scheduler can keep running after a turn ends.

- **S L2:** Cumulative prompt-token budget, repeated-call and repeated-failure breakers, and per-command shell timeouts. Evidence: [packages/core/src/runtime/limits.ts:73-84](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/limits.ts#L73-L84); [plugins/plugin-coding-tools/src/actions/bash.ts:76-78](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L76-L78) (verified)
  - *To reach the next level:* No step cap and no timeouts on every kind of step; L3 needs both.
- **C L2:** Limits cover the planner loop and shell runs; background sessions and scheduled tasks run outside the turn budget. Evidence: [packages/core/src/runtime/limits.ts:73-84](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/limits.ts#L73-L84); [plugins/plugin-coding-tools/src/actions/bash.ts:2001-2022](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L2001-L2022); [packages/agent/src/runtime/core-plugins.ts:79](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/core-plugins.ts#L79) (verified)
  - *To reach the next level:* Background and scheduled work don't count against the budget; L3 needs them included.
- **D L2:** Defaults are set in code and configurable by the operator. Evidence: [packages/core/src/runtime/limits.ts:83](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/core/src/runtime/limits.ts#L83) (verified)
  - *To reach the next level:* Tool calls are unbounded by default; L3 needs sensible defaults on every limit that the model can't raise.
- **B L1:** Background shell sessions and scheduled tasks can keep acting after a turn stops. Evidence: [plugins/plugin-coding-tools/src/actions/bash.ts:2001-2022](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/plugins/plugin-coding-tools/src/actions/bash.ts#L2001-L2022); [packages/agent/src/runtime/core-plugins.ts:79](https://github.com/elizaOS/eliza/blob/aa4f2b043b7af36517ce335319c99c68db449aa8/packages/agent/src/runtime/core-plugins.ts#L79) (verified)
  - *To reach the next level:* L2 needs moderate ceilings and nothing left running after stop.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: WEB_FETCH, WEB_SEARCH and browser plugin read arbitrary web content (plugins/plugin-coding-tools/src/index.ts:82) · [B] sensitive data/systems: User files outside a short blocklist plus provider and connector keys in the process environment (packages/agent/src/runtime/eliza.ts:1772) · [C] state change / egress: SHELL runs arbitrary host commands and WRITE/EDIT change files without approval (plugins/plugin-coding-tools/src/index.ts:78-80) · Same default session? Yes

## Highest-impact improvements
1. Default the runtime mode to the container sandbox (local-safe) on desktop, keeping host execution as an explicit operator choice. (C4 D L0→L3, +0.150 before caps; Playbook 3)
2. Require per-call human approval for shell commands and file writes that aren't on a parsed read-only allowlist, rendered by the host from the exact call. (C2 C L1→L3, +0.150 before caps; Playbook 5)
3. Ask for an explicit trust decision before loading hooks and instruction files from a project folder. (C6 S L0→L3, +0.225 before caps; Playbook 2)
4. Pass shell subprocesses an allowlisted environment without provider and connector keys. (C8 B L1→L2, +0.050 before caps; Playbook 4)
5. Require operator approval before plugins and hooks from the state and workspace folders load. (C7 D L0→L2, +0.100 before caps; Playbook 3)

## Re-audit log
- C8 B: L0 → L1. Re-read the L0 anchor: the keys reachable by subprocesses in the default config are model provider keys (connector tokens only when configured), which are moderately scoped rather than high-privilege; config.ts:1-10, eliza.ts:1772-1801 and run-shell.ts:215-216.
- C1 S: L0 → L1. Defending the L0: the file tools refuse credential folders such as ~/.ssh and ~/.aws (sandbox-service.ts:1-7) and actions are role-gated per requester, which partially narrows ambient authority even though the shell does not.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- Scored the standalone agent host on desktop from source; the packaged desktop app, Eliza Cloud containers, mobile/AOSP builds and the lean-chat profile have different plugin sets and defaults and were not scored.
- Not examined in depth: chat UI rendering of model output, the browser plugin internals, the wallet, MCP and orchestrator plugins (not loaded by default), and the cloud deployment code.
- The monorepo is very large; evidence concentrates on the agent host, core runtime, coding-tools plugin and config loading.
