|
| 1 | +# CodeDecay Threat Model |
| 2 | + |
| 3 | +Status: maintained security baseline for issue |
| 4 | +[#690](https://github.com/SubmuxHQ/CodeDecay/issues/690). |
| 5 | + |
| 6 | +This document describes how CodeDecay treats untrusted inputs, which |
| 7 | +capabilities are dangerous, and what the default-deny policy is intended to |
| 8 | +block. It is not a claim of perfect isolation. |
| 9 | + |
| 10 | +## Assets |
| 11 | + |
| 12 | +| Asset | Why it matters | |
| 13 | +| --- | --- | |
| 14 | +| Repository source and secrets in the working tree | Primary confidential and integrity target | |
| 15 | +| User-configured commands, probes, and product targets | Can mutate the machine or contact services | |
| 16 | +| Local memory, skills, ADRs, and docs | Can inject instructions into agent workflows | |
| 17 | +| Model/provider credentials and env vars | Exfiltration and unauthorized spend | |
| 18 | +| Generated experiment plans and agent patches | Untrusted executable suggestions | |
| 19 | +| Capability audit log and reports | Accountability and evidence integrity | |
| 20 | +| Git history, worktrees, and CI artifacts | Integrity of base/head comparison | |
| 21 | + |
| 22 | +## Trust zones |
| 23 | + |
| 24 | +```text |
| 25 | +Untrusted |
| 26 | + repository content, memory, MCP tool results, model output, |
| 27 | + agent patches, generated experiments, command stdout/stderr, |
| 28 | + telemetry exports |
| 29 | +
|
| 30 | +Configured (user-owned, still not fully trusted as code) |
| 31 | + .codedecay/config.*, design contracts, explicit CLI flags, |
| 32 | + safety.allowCommands, capabilityPolicy.allow entries |
| 33 | +
|
| 34 | +Trusted runtime boundary |
| 35 | + CodeDecay packages that authorize, audit, and spawn processes |
| 36 | + through packages/execution |
| 37 | +
|
| 38 | +Out of scope unless explicitly configured |
| 39 | + production deploy, production migrate, remote push/merge, |
| 40 | + package publish, cluster/infra mutation |
| 41 | +``` |
| 42 | + |
| 43 | +## Actors |
| 44 | + |
| 45 | +- **Developer / CI operator** — configures policy and intents. |
| 46 | +- **User-owned coding agent** — proposes edits and checks; never self-approves |
| 47 | + capabilities. |
| 48 | +- **External model provider** (Ollama / LiteLLM) — optional, explicit only. |
| 49 | +- **Malicious repository author** — plants prompt injection, symlink traps, |
| 50 | + or shell-substituted experiment plans. |
| 51 | +- **Compromised MCP/tool adapter** — returns forged success or hostile commands. |
| 52 | + |
| 53 | +## Data flows |
| 54 | + |
| 55 | +1. Git diff and file reads → deterministic analysis (`analyzer-js`). |
| 56 | +2. Config + memory + skills → redteam / agent packaging (suggestions only). |
| 57 | +3. Optional LLM investigation → untrusted hypotheses, never risk scores. |
| 58 | +4. `runConfiguredCommand` → capability authorize → safety denylist → spawn → |
| 59 | + audit. |
| 60 | +5. Reports / MCP / agent bundles → local artifacts; no hidden upload. |
| 61 | + |
| 62 | +## Attack surfaces and abuse cases |
| 63 | + |
| 64 | +| Abuse case | Default control | |
| 65 | +| --- | --- | |
| 66 | +| Prompt injection asks agent to read secrets and upload them | `secret.env` and `network` denied; untrusted intent sources cannot grant | |
| 67 | +| Generated experiment with `$(...)` / backticks | Command rejected before spawn | |
| 68 | +| Symlink escape from artifact directory | Canonical path must stay under allowed roots | |
| 69 | +| Config or memory text claims `allowCommands: true` without loaded config | Only normalized loaded config + caller intent authorize | |
| 70 | +| Agent declares a check “verified” | Agent text is never trusted evidence | |
| 71 | +| Destructive `rm -rf`, push, deploy, migrate | Pattern denylist in `checkCommandSafety` | |
| 72 | +| Silent model or network use | LLM provider defaults to `disabled`; network capability default-deny | |
| 73 | + |
| 74 | +## Capability policy (version 1) |
| 75 | + |
| 76 | +Capabilities: |
| 77 | + |
| 78 | +`model.call`, `command.execute`, `fs.read`, `fs.write`, `network`, |
| 79 | +`secret.env`, `package.install`, `process.start`, `browser`, `database`, |
| 80 | +`repo.access`, `git.mutate`, `artifact.persist`. |
| 81 | + |
| 82 | +Defaults deny elevated actions. `safety.allowCommands: true` is explicit |
| 83 | +user intent for `command.execute` on configured commands. It does not grant |
| 84 | +network, secrets, installs, git mutation, or model calls. |
| 85 | + |
| 86 | +Agent, memory, MCP, and generated-experiment text alone cannot flip a |
| 87 | +capability to allowed. |
| 88 | + |
| 89 | +## Residual risks |
| 90 | + |
| 91 | +- OS process isolation / sandboxing is platform-dependent; missing sandbox |
| 92 | + features must degrade to blocked or visibly weaker isolation, never silent |
| 93 | + full access (follow-up under #690). |
| 94 | +- Product health checks and capability `network` authorization validate each |
| 95 | + redirect hop against the allowlist and block credentials-in-URL plus common |
| 96 | + metadata endpoints. DNS-rebinding defenses for non-literal hostnames are |
| 97 | + available via `validateResolvedNetworkDestination` and still need broader |
| 98 | + call-site coverage. |
| 99 | +- MCP confirmation scopes still need per-tool narrowing beyond the shared |
| 100 | + authorize gate. |
| 101 | +- Command denylist is heuristic; allowlisted user commands can still be |
| 102 | + dangerous if the user authorizes them. |
| 103 | + |
| 104 | +## Audit |
| 105 | + |
| 106 | +Capability decisions append to |
| 107 | +`.codedecay/local/capability-audit.jsonl` when a repository cwd is available. |
| 108 | +Events cover requested, granted, denied, started, completed, timed-out, and |
| 109 | +cancelled phases for attributable review. |
0 commit comments