# Defense-in-Depth Score: goose

**Repo:** https://github.com/aaif-goose/goose · **Commit:** `591edd47cf2cfea4957d720c607cf2a4def8673d` · **Reviewed:** 2026-10-03
**What it is:** Extensible open-source AI agent (CLI + desktop) that installs, executes, edits and tests
**Category:** Coding
**Scored configuration:** Interactive `goose session` CLI, fresh install, no flags: default GooseMode (Auto), default platform extensions (Developer shell/write/edit, Summon, Extension Manager, Skills, etc.), started in a project directory.
**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 yes · external communication yes

## Score: 2.1 / 10.0 (Minimal)

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


goose ships in Auto mode, which runs every shell command, file write and extension call without asking, directly on the host with the user's full environment and credentials. A per-call Approve mode exists but is opt-in, and its enforcement does not cover every path. The most serious issue is that plugins committed to a repository's .agents/plugins folder are auto-enabled, so opening goose in a cloned repo can launch that repo's MCP servers and hook scripts with no prompt. Run it in a disposable VM or container and switch to Approve mode before pointing it at untrusted code.

## Critical gaps
- Plugins under the working directory's .agents/plugins are auto-enabled, and their hook commands (including SessionStart) and MCP servers run on the host with no trust prompt. (ASI06, ASI04; C6) — [crates/goose/src/plugins/discovery.rs:182](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L182); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138); [crates/goose/src/agents/agent.rs:458-461](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L458-L461); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130)
- A cloned repo's plugin MCP servers and hooks are launched by default without user consent. (ASI04; C7) — [crates/goose-cli/src/session/builder.rs:594-597](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/session/builder.rs#L594-L597); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138); [crates/goose/src/agents/extension_manager/stdio.rs:33-34](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L33-L34)
- In the default Auto mode a hijacked session can exfiltrate secrets and take irreversible actions with no human in the loop. (ASI01; C5) — [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161); [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25); [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733)
- Model-written shell commands run unsandboxed on the host with the full inherited environment. (ASI05; C4) — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/agents/platform_extensions/developer/shell.rs:751-756](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L751-L756)
- Every tool runs with the user's ambient credentials; nothing narrows or checks authority. (ASI03; C1) — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161)

## Criterion details

### C1 Identity & least privilege — 0.00 (high)

goose runs as the logged-in user with no narrowing of that authority. The shell tool starts bash with the full inherited environment, so every API key, cloud credential chain, SSH agent socket and gh/git login available to the user is available to model-written commands, and no subprocess anywhere clears its environment. There is no per-tool identity or authorization layer; in the default Auto mode every tool call is allowed. A hijacked session therefore holds the user's entire account across every service they are logged into.

- **S L0:** Shell and extensions run with the operator's ambient OS identity and full environment; no scoped or per-tool credentials. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/agents/platform_extensions/developer/shell.rs:751-756](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L751-L756); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
  - *To reach the next level:* No env scrubbing, scoped tokens, or deterministic pre-credential authorization gate.
- **C L0:** No authorization layer exists on any tool path; built-in shell, stdio MCP servers and hooks all inherit ambient credentials. — [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161); [crates/goose/src/agents/extension_manager/stdio.rs:33-34](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L33-L34); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130) (verified)
  - *To reach the next level:* No tool path is checked against a least-privilege policy.
- **D L0:** Default install runs every tool with the user's full privilege. — [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25); [crates/goose/src/agents/agent.rs:397](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L397) (verified)
  - *To reach the next level:* Default is full user authority; no read-only or minimal default role.
- **B L0:** A hijacked session can use all of the user's credentials across services (cloud CLIs, git push, SSH). — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
  - *To reach the next level:* Nothing limits reachable credentials to one system or to read-only use.
- **Cap:** none

### C2 Approval gates — 0.38 (high)

Approval is off by default: goose's default mode is Auto, which approves every tool call (shell, file writes, extension tools) without asking, and the first-run setup preselects Auto. An Approve mode exists that shows the exact tool name and arguments for each call and offers Allow, Always Allow, Deny and Cancel, with user-set per-tool permission levels. Even in Approve mode, the gate does not cover every path, plugin hooks run outside it, and Always Allow covers a whole tool such as the shell. Nothing in goose offers checkpoints or undo for shell side effects.

- **default configuration** (default; raw 0.00, cap G1 → 0.00)
  - **S L0:** In the default Auto mode the permission inspector returns Allow for every tool call; no human sees anything. — [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161); [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25) (verified)
    - *To reach the next level:* No approval exists in the scored default.
  - **C L0:** The most powerful tool (shell) is exempt along with every other tool in Auto mode. — [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161); [crates/goose/src/agents/platform_extensions/mod.rs:177-183](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/mod.rs#L177-L183) (verified)
    - *To reach the next level:* Shell and every other tool are ungated by default.
  - **D L0:** Approval is opt-in: GooseMode defaults to Auto and first-run configure preselects Auto. — [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25); [crates/goose/src/agents/agent.rs:397](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L397); [crates/goose-cli/src/commands/configure.rs:1556](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/commands/configure.rs#L1556) (verified)
    - *To reach the next level:* Approval must be enabled by the user; it is not on by default.
  - **B L0:** Shell runs any command with the user's credentials (force-push, rm -rf, sending data) and goose has no checkpoint or undo for those actions. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.); searched `rg -n -i 'checkpoint|undo|rollback'` in `crates/goose/src/agents crates/goose/src/permission` → 0 hits (No checkpoint/undo mechanism in the agent or permission code.) (verified)
    - *To reach the next level:* No checkpoints/rollback; irreversible external actions are reachable.
- **opt-in Approve mode (GOOSE_MODE=approve)** (alt; raw 0.38, cap G1 → 0.38) ← counted
  - **S L3:** Per-call prompt renders the exact tool name and arguments; user-set per-tool levels (always allow / ask / never) act as tiers and unknown tools default to approval. — [crates/goose-cli/src/session/mod.rs:2169-2173](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/session/mod.rs#L2169-L2173); [crates/goose/src/permission/permission_inspector.rs:164-170](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L164-L170); [crates/goose/src/permission/permission_inspector.rs:191-193](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L191-L193) (verified)
    - *To reach the next level:* No argument-level policy; Always Allow is per tool name (whole shell), not per parsed command.
  - **C L2:** All main-agent tools including MCP tools hit the gate, but the gate does not cover every path and plugin hooks run outside it. — [crates/goose/src/permission/permission_inspector.rs:191-193](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L191-L193); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130) (verified)
    - *To reach the next level:* Plugin hooks bypass the gate and coverage is incomplete; compound shell commands are not parsed.
  - **D L0:** Off by default; must be selected in configure or via GOOSE_MODE. — [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25); [crates/goose-cli/src/commands/configure.rs:1556](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/commands/configure.rs#L1556) (verified)
    - *To reach the next level:* Off by default.
  - **B L0:** Once approved, a shell call can still take irreversible actions with no checkpoint. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733) (verified)
    - *To reach the next level:* No checkpoints/rollback or previews for external actions.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

### C3 Tool & action scoping — 0.12 (high)

The default tool set is as broad as it gets: an arbitrary shell command string, file write/edit that accepts any absolute path on the machine, and an image reader that fetches any http(s) URL. There is no path containment, URL allowlist, or command allowlist on any built-in tool. Extensions can be toggled off as a whole, but the Developer extension with shell and write tools is on by default.

- **S L0:** Shell takes a raw command string passed to bash -c; write/edit resolve absolute paths without containment. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/agents/platform_extensions/developer/edit.rs:214-218](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/edit.rs#L214-L218) (verified)
  - *To reach the next level:* No allowlist validation (resolved-path containment, URL/host allowlists).
- **C L1:** Only read_image enforces a numeric bound (20 MB); no other built-in tool validates paths, URLs or commands, and read_image fetches arbitrary URLs. — [crates/goose/src/agents/platform_extensions/developer/image.rs:14](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/image.rs#L14); [crates/goose/src/agents/platform_extensions/developer/edit.rs:214-218](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/edit.rs#L214-L218); [crates/goose/src/agents/platform_extensions/developer/image.rs:171](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/image.rs#L171) (verified)
  - *To reach the next level:* Most built-in tools (shell, write, edit) do not validate inputs.
- **D L1:** Developer (shell, write, edit) and other extensions are enabled by default but can be disabled per extension. — [crates/goose/src/agents/platform_extensions/mod.rs:177-183](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/mod.rs#L177-L183) (verified)
  - *To reach the next level:* Default tool group still includes write and exec; no read-only default.
- **B L0:** A misused shell or write call reaches the whole machine. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/agents/platform_extensions/developer/edit.rs:214-218](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/edit.rs#L214-L218) (verified)
  - *To reach the next level:* Tools are not scoped to the project/workspace.
- **Cap:** none

### C4 Code-execution isolation — 0.20 (medium)

Model-written shell commands run directly on the host as the user through bash -c, with no container, OS sandbox or filtering. A --container flag can run stdio and built-in MCP extensions through docker exec in a container the user provides, but it does not cover every execution path. Repo-supplied plugin hooks and MCP servers also execute on the host.

- **default configuration** (default; raw 0.00, cap G1 → 0.00)
  - **S L0:** Same-user subprocess on the host; no isolation primitive exists anywhere in the crates. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); searched `rg -n -i 'seatbelt|sandbox-exec|landlock|bwrap|bubblewrap|seccomp|gvisor|firecracker'` in `crates` → 0 hits (No OS sandbox primitive anywhere in the Rust crates.) (verified)
    - *To reach the next level:* No OS-level separation (container, low-privilege user, sandbox profile).
  - **C L0:** Shell, hooks and stdio MCP servers all run on the host. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130); [crates/goose/src/agents/extension_manager/stdio.rs:33-34](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L33-L34) (verified)
    - *To reach the next level:* Main exec tool is not sandboxed.
  - **D L0:** No sandbox in the default configuration. — searched `rg -n -i 'seatbelt|sandbox-exec|landlock|bwrap|bubblewrap|seccomp|gvisor|firecracker'` in `crates` → 0 hits (No OS sandbox primitive anywhere in the Rust crates.); [crates/goose-provider-types/src/goose_mode.rs:23-25](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-provider-types/src/goose_mode.rs#L23-L25) (verified)
    - *To reach the next level:* No isolation on by default.
  - **B L0:** Host-equivalent: home directory, ~/.ssh, cloud credentials and full network egress are reachable. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
    - *To reach the next level:* Commands see the whole host filesystem, credentials and network.
- **opt-in --container (docker exec for stdio/builtin extensions)** (alt; raw 0.20, cap G1 → 0.20) ← counted
  - **S L2:** Extension processes run via docker exec inside a user-supplied container; hardening depends entirely on how the user built it. — [crates/goose/src/agents/extension_manager/stdio.rs:24-31](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L24-L31); [crates/goose-cli/src/cli.rs:141-146](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/cli.rs#L141-L146) (inferred)
    - *To reach the next level:* goose does not create or harden the container (non-root, dropped caps, no network).
  - **C L0:** Container coverage does not extend to every execution path. — [crates/goose/src/agents/extension_manager/stdio.rs:24-31](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L24-L31) (verified)
    - *To reach the next level:* Not every execution path is routed into the container.
  - **D L0:** Off unless --container is passed. — [crates/goose-cli/src/cli.rs:141-146](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/cli.rs#L141-L146) (verified)
    - *To reach the next level:* Off by default.
  - **B L1:** Configured extension env vars are forwarded with -e and container mounts/network are whatever the user chose. — [crates/goose/src/agents/extension_manager/stdio.rs:24-31](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L24-L31) (inferred)
    - *To reach the next level:* No goose-enforced workspace-only mount, egress control or secret exclusion.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

### C5 Untrusted input blast radius — 0.15 (high)

goose reads untrusted content routinely (repository files, shell and web output, MCP tool results, and MCP server instructions that are placed in the system prompt) and nothing structural limits what a hijacked session can do. In the default Auto mode the agent can read secrets, send them anywhere through the shell or the URL-fetching image tool, and take irreversible actions with no human involved. An optional prompt-injection pattern scanner exists but is off by default and only detects; the egress inspector only logs.

- **default configuration** (default; raw 0.00, cap C5-WORSTCASE → 0.00)
  - **S L0:** No taint tracking, Rule-of-Two enforcement or approval tied to untrusted content; egress inspector only logs. — searched `rg -n -i 'untrusted|taint|provenance|quarantin'` in `crates/goose/src/agents/agent.rs crates/goose/src/agents/tool_execution.rs crates/goose/src/agents/reply_parts.rs` → 0 hits (Tool results enter context with no provenance or untrusted marking.); [crates/goose/src/security/egress_inspector.rs:356-365](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/egress_inspector.rs#L356-L365) (verified)
    - *To reach the next level:* No capability is disabled or gated once untrusted content is read.
  - **C L0:** Tool results and MCP server instructions enter context with the same standing as the user's input. — [crates/goose/src/agents/extension_manager/mod.rs:620](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/mod.rs#L620); searched `rg -n -i 'untrusted|taint|provenance|quarantin'` in `crates/goose/src/agents/agent.rs crates/goose/src/agents/tool_execution.rs crates/goose/src/agents/reply_parts.rs` → 0 hits (Tool results enter context with no provenance or untrusted marking.) (verified)
    - *To reach the next level:* Untrusted sources are not distinguished.
  - **D L0:** The only related control (prompt-injection scanner) is off by default. — [crates/goose/src/security/mod.rs:66-72](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/mod.rs#L66-L72) (verified)
    - *To reach the next level:* No defense on by default.
  - **B L0:** A hijacked default session can read credentials, exfiltrate them via shell or URL fetch, and take irreversible actions unattended. — [crates/goose/src/permission/permission_inspector.rs:161](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/permission/permission_inspector.rs#L161); [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733); [crates/goose/src/agents/platform_extensions/developer/image.rs:171](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/image.rs#L171) (verified)
    - *To reach the next level:* Exfiltration and irreversible actions both happen without a human.
- **opt-in prompt-injection scanner (SECURITY_PROMPT_ENABLED)** (alt; raw 0.15, cap G1 → 0.15) ← counted
  - **S L1:** Pattern/ML classifier that asks the user only when a tool call looks malicious; detection only. — [crates/goose/src/security/mod.rs:66-72](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/mod.rs#L66-L72); [crates/goose/src/security/security_inspector.rs:34-40](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/security_inspector.rs#L34-L40) (verified)
    - *To reach the next level:* Detection is bypassable; no structural Rule-of-Two limit.
  - **C L1:** Scans tool requests; does not mark untrusted sources or MCP instructions. — [crates/goose/src/security/mod.rs:66-72](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/mod.rs#L66-L72) (verified)
    - *To reach the next level:* Most untrusted sources are not handled.
  - **D L0:** Off by default. — [crates/goose/src/security/mod.rs:66-72](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/security/mod.rs#L66-L72) (verified)
    - *To reach the next level:* Off by default.
  - **B L0:** Missed detections still allow unattended exfiltration and irreversible actions. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L732-L733) (verified)
    - *To reach the next level:* Undetected injections retain full capability.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

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

A cloned repository can change goose's behavior with no prompt. Plugins placed under .agents/plugins in the working directory are discovered and auto-enabled, their MCP servers are launched, and their hooks.json commands (including SessionStart) run through sh on the host. .goosehints and AGENTS.md from the project are loaded silently into the system prompt, and the model can write those files (or a new plugin) with its unrestricted write and shell tools, so an injection can persist into later sessions and to anyone else who clones the repo.

- **S L0:** Repo-controlled files add MCP servers and hooks with no prompt; instruction files load silently. — [crates/goose/src/plugins/discovery.rs:182](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L182); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138); [crates/goose/src/agents/agent.rs:458-461](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L458-L461); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130); [crates/goose/src/agents/prompt_manager.rs:90](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/prompt_manager.rs#L90) (verified)
  - *To reach the next level:* No workspace-trust decision before project plugins, hooks or MCP servers activate.
- **C L0:** No persistence path is controlled: project plugins, hooks, hint files and model writes to them are all ungated. — [crates/goose-cli/src/session/builder.rs:594-597](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/session/builder.rs#L594-L597); searched `rg -n -i trust` in `crates/goose/src/plugins crates/goose/src/hooks` → 0 hits (No workspace-trust decision guards project-scope plugins, their hooks, or their MCP servers.); [crates/goose/src/hints/load_hints.rs:19-22](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hints/load_hints.rs#L19-L22) (verified)
  - *To reach the next level:* No store or auto-loaded file is gated.
- **D L1:** Local single-user CLI; sessions are per-user, but repo files act on every user who opens the project and nothing stops the model writing them. — [crates/goose/src/plugins/discovery.rs:182](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L182); [crates/goose/src/hints/load_hints.rs:19-22](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hints/load_hints.rs#L19-L22) (verified)
  - *To reach the next level:* Project-scope context is shared with every user of the repo and writable by the model.
- **B L0:** Poisoned plugins/hints persist in the repo, affect other users who clone it, and can trigger code execution (hooks) and tool use. — [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138) (verified)
  - *To reach the next level:* Poisoned context persists across sessions and users and triggers tool use.
- **Cap:** C6-REPOCONFIG — Files in the working directory (.agents/plugins/*) enable MCP servers and hook commands without any user trust decision.

### C7 Third-party extensions — 0.07 (high)

Third-party code runs with the agent's full access and little verification. User-configured MCP extensions are typically npx/uvx packages launched unpinned; goose checks them against the OSV malicious-package list, but that check only covers npx/uvx and fails open otherwise. Worse, plugins committed to a project's .agents/plugins directory are enabled on discovery, so opening goose in a cloned repo launches that repo's MCP servers and hook scripts without consent. Extension processes run as the same user with the inherited environment.

- **S L1:** User-chosen extension sources, typically unpinned; OSV malware denylist check for npx/uvx only. — [crates/goose/src/agents/extension_malware_check.rs:44-47](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_malware_check.rs#L44-L47) (verified)
  - *To reach the next level:* No version pinning or integrity verification of extensions.
- **C L0:** No extension type is verified: project plugins, hooks and non-npx/uvx stdio servers bypass even the OSV check. — [crates/goose/src/agents/extension_malware_check.rs:44-47](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_malware_check.rs#L44-L47); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138) (verified)
  - *To reach the next level:* No extension type gets pinning or integrity checks.
- **D L0:** Workspace files add extensions silently (project plugins auto-enabled). — [crates/goose/src/plugins/discovery.rs:182](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L182); [crates/goose/src/plugins/discovery.rs:138](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/plugins/discovery.rs#L138); [crates/goose-cli/src/session/builder.rs:594-597](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/session/builder.rs#L594-L597) (verified)
  - *To reach the next level:* Workspace can add extensions without consent.
- **B L0:** Extensions run as the same user with the full inherited environment plus configured envs. — [crates/goose/src/agents/extension_manager/stdio.rs:33-34](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/extension_manager/stdio.rs#L33-L34); [crates/goose/src/hooks/mod.rs:1126-1130](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/hooks/mod.rs#L1126-L1130); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
  - *To reach the next level:* No env scrubbing or per-extension sandbox.
- **Cap:** C7-RCELOAD — By default goose launches MCP servers and runs hook commands from a cloned repo's .agents/plugins without consent.
- **Notes:** The OSV malware check is on by default (not opt-in); D is L0 because workspace files add extensions silently, so G1 does not apply.

### C8 Secrets & sensitive-data protection — 0.20 (high)

Provider API keys go to the OS keychain by default, falling back to an owner-only (0600) file. Beyond that there is little protection: shell commands inherit every environment secret and their output goes to the model, nothing redacts secrets from tool results, logs or saved transcripts (the only redaction is for telemetry error strings), and the CLI writes full LLM request payloads to local log files by default. Telemetry is opt-in.

- **S L1:** Keychain/0600 storage at rest, but no masking or redaction on logs, tool output or model-bound messages beyond telemetry errors. — [crates/goose-cli/Cargo.toml:104](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/Cargo.toml#L104); [crates/goose/src/providers/private_file.rs:251](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/providers/private_file.rs#L251); [crates/goose/src/posthog.rs:533](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/posthog.rs#L533) (verified)
  - *To reach the next level:* No type-level masking or log filters on main paths.
- **C L1:** Only the telemetry error path redacts; LLM request logs, transcripts, subprocess env and model messages are unprotected. — [crates/goose/src/posthog.rs:533](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/posthog.rs#L533); [crates/goose/src/providers/utils.rs:86](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/providers/utils.rs#L86); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
  - *To reach the next level:* Logs and transcripts are not redacted.
- **D L1:** Telemetry is opt-in, but full LLM request payload logging is on by default in the CLI and unredacted. — [crates/goose/src/posthog.rs:50-51](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/posthog.rs#L50-L51); [crates/goose-cli/src/logging.rs:14](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/logging.rs#L14); [crates/goose/src/providers/utils.rs:86](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/providers/utils.rs#L86) (verified)
  - *To reach the next level:* Logging defaults keep full payloads; no redaction to disable.
- **B L0:** Long-lived provider keys and every user credential in the environment are reachable by every shell subprocess. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:751-756](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L751-L756); searched `rg -n env_clear` in `crates` → 0 hits (No subprocess in any crate clears the inherited environment.) (verified)
  - *To reach the next level:* Long-lived high-privilege keys are reachable by the model's commands.
- **Cap:** none

### C9 Audit & traceability — 0.50 (high)

Every message, including tool calls with arguments and results, is written per message to a SQLite session database in the user's data directory, and sub-agent sessions are linked to their parent. That gives a usable local transcript. It is not tamper-evident: the agent's own shell runs as the same user and can edit or delete it, and there is no actor attribution separating approver from agent or standard audit export by default.

- **S L2:** Structured transcript of messages including tool requests/responses with timestamps. — [crates/goose/src/session/session_manager.rs:1945](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/session/session_manager.rs#L1945); [crates/goose/src/agents/agent.rs:323](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L323) (verified)
  - *To reach the next level:* No approver/actor attribution or cross-agent correlation beyond parent session id.
- **C L2:** All tool calls in the main session and sub-agent sessions (linked via parent_session_id) are recorded; approvals and plugin hook runs are not shown to be recorded. — [crates/goose/src/agents/agent.rs:323](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L323); [crates/goose/src/agents/platform_extensions/summon.rs:627-632](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/summon.rs#L627-L632) (verified)
  - *To reach the next level:* Approvals/denials and hook executions are not verified as recorded.
- **D L2:** On by default, stored in the data dir outside the workspace, but the same-user shell can alter it. — [crates/goose/src/session/session_manager.rs:961](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/session/session_manager.rs#L961) (verified)
  - *To reach the next level:* Written by a component the model's shell can modify.
- **B L2:** Messages are inserted as they are produced and write errors propagate. — [crates/goose/src/agents/agent.rs:323](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L323); [crates/goose/src/session/session_manager.rs:1945](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/session/session_manager.rs#L1945) (verified)
  - *To reach the next level:* No guarantee of full replay or fail-closed recording.
- **Cap:** none

### C10 Limits & kill switch — 0.40 (high)

The main loop stops after 1,000 turns and shell commands get a 300-second default timeout, but the model sets timeout_secs itself and a value of 0 disables the timeout. Sub-agents get a fresh 25-turn budget each (model-adjustable), cannot delegate further, and at most 5 run in the background. There is no cost or token cap. Ctrl-C cancels the loop and kills the shell process, but not its process group, so backgrounded children can survive.

- **S L2:** Iteration cap plus per-execution shell timeout enforced in code; no cost cap. — [crates/goose/src/agents/agent.rs:86](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L86); [crates/goose/src/agents/platform_extensions/developer/shell.rs:597](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L597); searched `rg -n -i 'cost_limit|max_cost|spend_limit|budget_usd|max_tokens_per_session'` in `crates/goose/src` → 0 hits (No session cost or token cap.) (verified)
  - *To reach the next level:* No wall-clock or token/cost cap; no rate limits on side-effecting tools.
- **C L2:** Top-level loop plus tool timeouts; sub-agents get their own fresh budget rather than sharing the parent's. — [crates/goose/src/agents/subagent_task_config.rs:9](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/subagent_task_config.rs#L9); [crates/goose/src/agents/platform_extensions/summon.rs:1369-1370](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/summon.rs#L1369-L1370); [crates/goose/src/agents/platform_extensions/summon.rs:559-562](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/summon.rs#L559-L562) (verified)
  - *To reach the next level:* Sub-agents do not count against the parent's budget.
- **D L1:** Defaults are large (1000 turns) and the model can raise its own limits via timeout_secs (0 = unlimited) and delegate max_turns. — [crates/goose/src/agents/agent.rs:86](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/agent.rs#L86); [crates/goose/src/agents/platform_extensions/developer/shell.rs:182-185](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L182-L185); [crates/goose/src/agents/platform_extensions/developer/shell.rs:597](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L597); [crates/goose/src/agents/platform_extensions/summon.rs:1688-1691](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/summon.rs#L1688-L1691) (verified)
  - *To reach the next level:* The model can raise or remove its limits.
- **B L1:** Stopping kills only the shell pid; background processes can outlive the session and ceilings are very large. — [crates/goose/src/agents/platform_extensions/developer/shell.rs:603-606](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose/src/agents/platform_extensions/developer/shell.rs#L603-L606); [crates/goose-cli/src/session/mod.rs:1321-1322](https://github.com/aaif-goose/goose/blob/591edd47cf2cfea4957d720c607cf2a4def8673d/crates/goose-cli/src/session/mod.rs#L1321-L1322) (verified)
  - *To reach the next level:* Stop does not kill the process group; ceilings are hours-scale.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: Repo files, shell/web output, MCP tool results and MCP server instructions in the system prompt (crates/goose/src/agents/extension_manager/mod.rs:620) · [B] sensitive data/systems: Full inherited environment and user credentials reachable from shell (crates/goose/src/agents/platform_extensions/developer/shell.rs:732-733) · [C] state change / egress: Unrestricted shell, file write and URL fetch, auto-approved in Auto mode (crates/goose/src/permission/permission_inspector.rs:161) · Same default session? Yes

## Highest-impact improvements
1. Require an explicit workspace-trust decision before enabling project-scope plugins, their MCP servers and hooks. — C6 S L0→L3, +0.225 before caps (Playbook 2)
2. Make Approve (or SmartApprove with read-only allowlist) the default GooseMode instead of Auto. — C2 D L0→L3, +0.150 before caps (Playbook 5)
3. Do not auto-enable newly discovered project plugins; show the exact commands and ask once per plugin version. — C7 D L0→L3, +0.150 before caps (Playbook 3)
4. Run shell commands in an OS sandbox (Seatbelt/Landlock+seccomp) limiting writes to the workspace and denying network by default. — C4 S L0→L3, +0.225 before caps (Playbook 3)
5. Scrub the environment passed to shell and extension subprocesses to an allowlist. — C8 B L0→L1, +0.050 before caps (Playbook 4)

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- Scored the CLI default; the desktop app (ui/desktop) and goose-server/ACP paths share the core crate and the same GooseMode default but their UI approval rendering was not reviewed in depth.
- The scheduler, gateway (Telegram), roaming and local-inference subsystems were not examined in depth.
- No reviewer-injection attempts were found in the repository text that was read.
- C4 alt S/B are inferred: goose does not build the container used by --container, so its hardening depends on the user.
