fix(#24): redact marker must have no shell metacharacters#53
Merged
dwgx merged 1 commit intodwgx:masterfrom Apr 24, 2026
Merged
fix(#24): redact marker must have no shell metacharacters#53dwgx merged 1 commit intodwgx:masterfrom
dwgx merged 1 commit intodwgx:masterfrom
Conversation
Reproducer: Claude Code v2.1.114 (Opus 4.7) routed through the proxy
emits a bash tool call whose command includes the redaction marker
verbatim, e.g.:
cd (internal path redacted) && git log --all --oneline -30
zsh parses `cd word(qualifier)` as glob-qualifier syntax, reads the
first char of "internal" as a qualifier flag, and fails with:
(eval):1: unknown file attribute: i
The model sees the cryptic error, can't recover, and starts replying
with confused meta-text ("the user seems to have pasted a system
prompt along with a shell error about an invalid file test operator")
instead of retrying.
Root cause: commit 9120b8b picked `(internal path redacted)` because
"a multi-word parenthesised phrase cannot be tokenised as a path or
identifier." True for file APIs — but parens are first-class shell
metacharacters (subshell, glob qualifier). The marker had to satisfy
file-API safety AND shell safety AND anti-loop shape at once; the
old marker only satisfied the first two.
Fix: drop every shell metacharacter from the marker. Use a plain
ASCII multi-word phrase: "redacted internal path". If a model still
echoes it into shell the words become separate argv entries and `cd`
or `Read` fails with a clean, recoverable error (too many arguments
/ single ENOENT) — never the cryptic glob-qualifier error. The
marker still cannot be parsed as a path (no `/`, no `.`) or as an
identifier (contains whitespace), so the drift-probe regressions
(./tail, [internal], <redacted-path>) remain fixed.
Adds a REDACTED_PATH marker-shape regression suite asserting:
1. No character in `()[]{}<>|&;$\`"'\\*?` appears in the marker.
2. The marker has no `/` or `\\`, contains whitespace, and is
multi-word — so it cannot reappear as a path or identifier.
Tests: 61/61 pass (59 existing + 2 new marker-shape guards).
Closed
dwgx
added a commit
that referenced
this pull request
Apr 25, 2026
…ly-zhang to S+ - baily-zhang PR #61 (Opus 4.7 multimodal context bloat) — third major contribution after #36 and #45, now de-facto maintainer of the reuse-fingerprint / trajectory-offset machinery - abwuge PR #58 (docker/nginx deploy fix) — first-time contributor, +3/-2 surgical, unblocked the docker-compose Restart loop - aict666 PR #54 (tool preamble slimming + redact marker 6th-gen U+2026 ellipsis + identity coverage extension) — fourth major contribution - aict666 PR #53 (redact marker shell-safety regression) — second contribution, was missing from the prior credits update - baily-zhang upgraded from S to S+ (parity with aict666)
dwgx
added a commit
that referenced
this pull request
Apr 25, 2026
The Pages site at dwgx.github.io/WindsurfAPI/ had only 4 names listed in the footer (dd373156, colin1112a, motto1, youfak). 8 contributors were missing from the public site even though most of them landed S+/S level fixes (aict666 #44/#51/#53/#54, baily-zhang #36/#45/#61, smeinecke #43, abwuge #58). Adds a dedicated `#contributors` section before the footer with one card per contributor: avatar, GitHub link, weight badge (S+/S/A+/A/B+), PR list, and a one-paragraph 繁體中文 description of what each fix actually solved. Cards reuse the existing panel-card warm/coral palette to fit the site's aesthetic. Footer one-liner is also expanded to all 8 names ordered by weight, with a "完整名單 ↑" anchor back to the new section. CSS additions: contrib-grid, contrib-card, contrib-avatar, contrib-weight + 5 weight-tier classes (-S-plus, -S, -A-plus, -A, -B-plus). All gradient/hover behaviour matches the existing panel-card styling.
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.
Problem
Claude Code v2.1.114 (Opus 4.7) routed through the proxy still derails on tool use — not because of the old preamble (PR #51 fixed that), but because the model echoes the redaction marker
(internal path redacted)into a bash tool call:zsh parses
cd word(qualifier)as glob-qualifier syntax, reads theiofinternalas a qualifier flag, and dies with the crypticunknown file attribute: i. The model can't recover from that error shape and starts replying with confused meta-text ("the user seems to have pasted a system prompt along with a shell error...") instead of retrying the tool.Root cause
Commit
9120b8bpicked(internal path redacted)with the rationale "a multi-word parenthesised phrase cannot be tokenised as a path or identifier." True for file APIs — but parens are first-class shell metacharacters (subshell in POSIX sh/bash, glob qualifier in zsh). The marker has to satisfy file-API safety AND shell safety AND anti-loop shape simultaneously; the old marker only cleared the first two.Fix
Drop every shell metacharacter from the marker. Use a plain ASCII multi-word phrase:
()[]{}<>|&;$`"'\*?→ no shell parser treats it specially./, no.→ does not look like a path, so the sonnet/opus drift-probe regressions (./tail,[internal],<redacted-path>) do not come back.cd/Readfails with a clean recoverable error (cd: too many arguments, single ENOENT) — never the cryptic glob-qualifier error.No other changes: the patterns, the streaming cut-point logic, and the
sanitizeToolCallshape are untouched.Regression guard
Adds a new suite
REDACTED_PATH marker shape (shell-safety regression)with two asserts:/[()\[\]{}<>|&;$`\\"'*?]/./, no\\, contains whitespace, multi-word.Both guards run against the actual output of
sanitizeText('/tmp/windsurf-workspace'), so any future marker change must pass them or break the build.Tests
npm test— 61/61 pass (59 existing + 2 new marker-shape guards).Risk
Low. Only the display string changes. All 19 call sites pass the string through opaquely; none parse or pattern-match on the marker value. Clients that previously rendered
(internal path redacted)in transcripts will now renderredacted internal path— the information conveyed is identical and the wording reads as prose in both English and CJK contexts.