Fix auto-mode allowing quoted shell redirect writes and dangerous flags - #601
Merged
TheGreatAxios merged 3 commits intoAug 24, 2026
Merged
Conversation
TheGreatAxios
force-pushed
the
cl-6703-fix-auto-mode-allowing-quoted-shell-redirect-writes
branch
from
August 24, 2026 05:36
bb2c272 to
b672855
Compare
Collaborator
Author
|
Addressed both review items:
Rebased onto latest `origin/main`. `bun run check` green: 5423 tests, 0 failures. |
TheGreatAxios
enabled auto-merge (squash)
August 24, 2026 05:37
The auto-shell policy blanked quoted spans to whole-space before matching its rules, so a quoted redirect target, a quoted -c/-i flag, a quoted install subcommand, or a quoted argv0 all read as absent text and slipped past deny/ask. Replace the blanket blank with quote-aware dequoting that mirrors real shell semantics: quote characters are dropped and their content stays literal, except the handful of characters that are only operators outside quotes (> < | & ; `) which are neutralized when quoted, so a literal '>' in a commit message still can't be mistaken for a redirect. Also widen the file-mutation redirect pattern to recognize the `>|` / `>>|` clobber form, which never matched at all. One tokenizer fix covers all three bypasses since they share the same root cause (stripQuoted) and the same call site (matchAutoShellRule).
dequoteForMatching tracked quote state without escape awareness, so a backslash-escaped quote (\") still toggled quote state the same as a real one. In real bash \" is a literal quote character that never opens or closes a quoted span, so an operator or flag that follows is genuinely unquoted. Skip the escaped character without touching quote state. Also narrow the CHANGELOG's nested bash -c claim to what the tests actually cover (one level of quoting inside -c), not true multi-level nested-shell parsing, which remains a known gap tracked separately.
TheGreatAxios
force-pushed
the
cl-6703-fix-auto-mode-allowing-quoted-shell-redirect-writes
branch
from
August 24, 2026 05:46
b672855 to
ef44efb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
One root cause, one fix.
AUTO_SHELL_RULESmatching (matchAutoShellRuleinsrc/permission/auto-shell-policy.ts) ran every rule againststripQuoted(command), which replaced entire quoted spans with a blank space before matching. That erases the character class of a quoted redirect target, a quoted-c/-iflag, a quotedinstallsubcommand, and a quoted argv0 alike — so quoting any of them defeats every CMD-anchored rule and the redirect pattern. All three tickets are the same bypass surfacing through different rules, at the same call site.Fix
Replaced
stripQuotedwithdequoteForMatching: a quote-aware pass that mirrors real shell semantics — quote characters are dropped and their content stays literal (so a quoted flag/program name/redirect target is visible to the rules exactly as the shell would see it), except the small set of characters that are only operators outside quotes (> < | & ; \``), which are neutralized when they appear inside a quote so a literal>` in a commit message can't be mistaken for a redirect.Also widened the file-mutation redirect regex to accept an optional
|immediately after>/>>(>|,>>|bash clobber forms), which the old pattern rejected outright.Single fix, three sites covered — no separate patches needed since all three collapse to the same
matchAutoShellRulecall path.Tickets and tests
All in
src/permission/classify-security.test.ts, describe blocks named after each ticket.describe("CL-6703 — quoted redirect targets still deny file-mutation"):"a quoted redirect target denies","a quoted fd-qualified redirect target (1>\"file\") denies","a nested bash -c form with a quoted redirect denies", plus the negative"a quoted '>' inside non-redirect text does not false-positive".describe("CL-6702 — bash clobber redirects match file-mutation"):"echo hi >|path denies","echo hi >>|path denies".describe("CL-6697 — quoted dangerous flags and program names still deny/ask"):"a quoted -c interpreter one-liner denies","a quoted sed -i denies","a quoted npm install asks","a quoted upload-tool argv0 (curl) asks", plus the negative"an innocent quoted argument interior does not false-positive".Verified each of the 8 new bypass-reproduction tests fails against the pre-fix
auto-shell-policy.ts(git-stashed) and passes with the fix.Gate
bun run check(lint, typecheck, build, full test suite) is green: 5397 tests pass, 0 fail.Files changed
src/permission/auto-shell-policy.ts—dequoteForMatchingreplacesstripQuoted; redirect regex accepts>|/>>|.src/permission/classify-security.test.ts— regression tests above.CHANGELOG.md— Unreleased entry.Diff kept to
auto-shell-policy.tsand its test file only;gate.ts/classify.tsuntouched per the heads-up on PR #598.