Summary
The approval gate in tools/approval.py (detect_dangerous_command, DANGEROUS_PATTERNS, and the hardline list) is an in-process heuristic per SECURITY.md section 2.4: it pattern-matches shell command strings. It misses a class of dangerous commands that are simple compositions of standard shell idioms the regex tables do not model. This is CWE-184 (Incomplete List of Disallowed Inputs): the denylist is structurally incomplete.
This issue is the RG-4 follow-up to advisory GHSA-6cjf-cff6-j9mg, which the maintainers closed out-of-scope under SECURITY.md section 3.2 with an explicit invitation to file the bypass class as a regular issue plus a PR that extends the pattern table and adds regression tests. Per section 3.2 this is not a security-boundary report; the boundary remains OS-level isolation (section 2.2). It is hardening of the cooperative-mode catch.
Idiom classes the gate misses
A dangerous command the pattern tables already match can be hidden behind any of these, individually or composed:
${IFS} expansion (and ${IFS} modifier forms) and bare $IFS, used in place of spaces so the token structure does not match.
- ANSI-C quoting:
$'...' with hex, octal, named, or unicode escapes, expressing a command name entirely as escape sequences.
- Empty / adjacent quote splits:
"" or '' inserted inside a command word.
eval / command / builtin wrapper prefixes: the inner command is not visible to a command-position match while wrapped.
chmod octal-prefixed world/other-writable modes (0777, 0666): the existing pattern only covered the bare-octal form.
- Alternate shell binaries:
dash, ash invoked with -c (the recognised set was bash|sh|zsh|ksh).
- base64-decode piped into a shell:
... | base64 -d | sh, including through command wrappers such as | sudo bash or | timeout 5 sh.
- Shell execution of a script in a world-writable / transient path:
bash /tmp/x.sh and similar, where the dangerous content is in the file and invisible to the command string.
Scope
The fix decodes the reducible idioms in pre-match normalization and widens or adds DANGEROUS_PATTERNS entries for the idiom classes that are their own structure. Decoding the payload inside $(...) or backtick command substitution is explicitly out of scope: the gate flags the wrapper structure, it does not evaluate opaque inner content.
Proposed fix
A PR implementing this with per-class regression tests (true-positive catch plus false-positive guard) follows and links back to this issue.
Notes
- No change to the security posture. The boundary remains OS-level isolation (section 2.2); this only makes the in-process heuristic catch more.
- PoC hygiene: specific bypass strings live in the PR's regression-test fixtures, not in this issue.
Summary
The approval gate in
tools/approval.py(detect_dangerous_command,DANGEROUS_PATTERNS, and the hardline list) is an in-process heuristic per SECURITY.md section 2.4: it pattern-matches shell command strings. It misses a class of dangerous commands that are simple compositions of standard shell idioms the regex tables do not model. This is CWE-184 (Incomplete List of Disallowed Inputs): the denylist is structurally incomplete.This issue is the RG-4 follow-up to advisory
GHSA-6cjf-cff6-j9mg, which the maintainers closed out-of-scope under SECURITY.md section 3.2 with an explicit invitation to file the bypass class as a regular issue plus a PR that extends the pattern table and adds regression tests. Per section 3.2 this is not a security-boundary report; the boundary remains OS-level isolation (section 2.2). It is hardening of the cooperative-mode catch.Idiom classes the gate misses
A dangerous command the pattern tables already match can be hidden behind any of these, individually or composed:
${IFS}expansion (and${IFS}modifier forms) and bare$IFS, used in place of spaces so the token structure does not match.$'...'with hex, octal, named, or unicode escapes, expressing a command name entirely as escape sequences.""or''inserted inside a command word.eval/command/builtinwrapper prefixes: the inner command is not visible to a command-position match while wrapped.chmodoctal-prefixed world/other-writable modes (0777,0666): the existing pattern only covered the bare-octal form.dash,ashinvoked with-c(the recognised set wasbash|sh|zsh|ksh).... | base64 -d | sh, including through command wrappers such as| sudo bashor| timeout 5 sh.bash /tmp/x.shand similar, where the dangerous content is in the file and invisible to the command string.Scope
The fix decodes the reducible idioms in pre-match normalization and widens or adds
DANGEROUS_PATTERNSentries for the idiom classes that are their own structure. Decoding the payload inside$(...)or backtick command substitution is explicitly out of scope: the gate flags the wrapper structure, it does not evaluate opaque inner content.Proposed fix
A PR implementing this with per-class regression tests (true-positive catch plus false-positive guard) follows and links back to this issue.
Notes