fix(#4926): env-assignment redaction must not eat URL query tails

Codex re-gate: the env/AUTH '=' redaction regex matched 'token=' INSIDE a URL
(?token=...&mode=debug&signature=...) before the dedicated URL-query redactor,
and its \S+ value swallowed the rest of the URL incl later params + closing
quote. Anchor the env-assignment match to a shell-token boundary (^|[\s;|(]) so
it can't match keys preceded by ? or & — URL query params are left to the
dedicated query-param redactor, which masks the secret-looking ones while
preserving the command tail. + regression tests (URL-tail-preserved,
benign-PATH-not-over-redacted).
This commit is contained in:
nesquena-hermes committed 2026-06-25 17:58:12 +00:00
1 parent ed21bd20cd
commit 64cb4cef4e
2 files changed
+21 -2

No files matched your search

+2 -2
View File
@@ -12525,10 +12525,10 @@ function _redactToolTargetLabel(value){
// the expanded shell card can't leak a key on a non-first line (#4926). Keys
// matched case-insensitively: *(TOKEN|API_KEY|APIKEY|SECRET|PASSWD|PASSWORD|
// ACCESS_KEY|PRIVATE_KEY|AUTH|CREDENTIAL|SESSION_KEY|CLIENT_SECRET)*.
.replace(/(\b[A-Za-z0-9_]*(?:TOKEN|API[_-]?KEY|SECRET|PASSWD|ACCESS[_-]?KEY|PRIVATE[_-]?KEY|CREDENTIALS?|CLIENT[_-]?SECRET|SESSION[_-]?KEY)[A-Za-z0-9_]*\s*=\s*)(?:"[^"]*"|'[^']*'|\S+)/gi,'$1[redacted]')
.replace(/(^|[\s;|(])([A-Za-z0-9_]*(?:TOKEN|API[_-]?KEY|SECRET|PASSWD|ACCESS[_-]?KEY|PRIVATE[_-]?KEY|CREDENTIALS?|CLIENT[_-]?SECRET|SESSION[_-]?KEY)[A-Za-z0-9_]*\s*=\s*)(?:"[^"]*"|'[^']*'|\S+)/gi,'$1$2[redacted]')
// AUTH-family env assignment, but only the `=` form (the `Authorization:`
// header colon form is handled separately below, and must not be eaten here).
.replace(/(\b[A-Za-z0-9_]*AUTH[A-Za-z0-9_]*\s*=\s*)(?:"[^"]*"|'[^']*'|\S+)/gi,'$1[redacted]')
.replace(/(^|[\s;|(])([A-Za-z0-9_]*AUTH[A-Za-z0-9_]*\s*=\s*)(?:"[^"]*"|'[^']*'|\S+)/gi,'$1$2[redacted]')
// --token / --api-key / --secret style flags.
.replace(/(--(?:token|api[_-]?key|secret|access[_-]?key|client[_-]?secret|auth[_-]?token)(?:=|\s+))(?:"[^"]*"|'[^']*'|\S+)/gi,'$1[redacted]')
// Authorization: Bearer/Bot/Token <token> (header or curl -H form):
@@ -152,3 +152,22 @@ def test_password_redaction_still_works(driver_path):
assert "hunter2" not in out["lead"]
assert "topsecret" not in out["lead"]
assert "[redacted]" in out["lead"]
def test_url_query_redaction_preserves_command_tail(driver_path):
"""#4926 gate: redacting a secret URL query param must NOT swallow the rest
of the URL (later params + closing quote). Regression for the env-assignment
regex over-matching `token=` inside a URL and eating the tail with \\S+."""
out = _run(driver_path, {"args": {"command": "curl 'https://x.com/cb?token=tok_leak&mode=debug&signature=sig_leak'"}})
lead = out["lead"]
assert "tok_leak" not in lead and "sig_leak" not in lead
# The non-secret param + closing quote must survive (no tail truncation).
assert "mode=debug" in lead
assert lead.rstrip().endswith("'")
def test_benign_assignment_not_over_redacted(driver_path):
"""A non-secret assignment like PATH= must not be mangled."""
out = _run(driver_path, {"args": {"command": "export PATH=/usr/bin:/bin\necho ok"}})
assert "/usr/bin:/bin" in out["lead"]
assert "echo ok" in out["lead"]