Skip to content

fix(redact): strip complete CSI sequences before prefix masking (#81012) - #81062

Closed
Enough1122 wants to merge 1 commit into
NousResearch:mainfrom
Enough1122:fix/81012-csi-sgr-redact
Closed

fix(redact): strip complete CSI sequences before prefix masking (#81012)#81062
Enough1122 wants to merge 1 commit into
NousResearch:mainfrom
Enough1122:fix/81012-csi-sgr-redact

Conversation

@Enough1122

Copy link
Copy Markdown
Contributor

Fixes #81012

A vendor-prefix token wrapped in ANSI color codes (e.g. \x1b[32msk-…) leaked ENTIRELY through redact_sensitive_text. The previous control-char strip removed only the bare ESC byte, leaving the trailing [32m chars intact — and the literal m defeated _PREFIX_RE's (?<![A-Za-z0-9_-]) lookbehind on a prefix token that followed immediately after the sequence.

Fix

Compile _CSI_SEQUENCE_RE matching the complete CSI leg of ECMA-48 (parameter / intermediate / final byte ranges, including the ? private-mode prefix), strip CSI sequences as a unit before the control-char pass, and treat CSI-internal bytes as collapsible in the span validation so the join isn't rejected when a CSI sequence sits inside the matched token span.

Reuses the CSI leg of tools/ansi_strip.py so the two scrubbers cannot drift.

Regression tests

The new TestCSISplitTokens class covers the leak shapes from the issue:

  • CSI directly glued to sk- (no space) — the primary leak from the report
  • CSI after the prefix inside the token body (sk-\x1b[32mbody\x1b[0m)
  • Bold + color SGR (\x1b[1;31m) — multi-byte param leg
  • 256-color SGR (\x1b[38;5;196m) — even more param bytes
  • True-color SGR (\x1b[38;2;255;0;0m) — boundary on the 5/6 char leg
  • DEC private-mode CSI (\x1b[?25h) — ? param byte
  • ghp_ prefix wrapped in CSI — confirms fix is not sk--specific
  • OSC hyperlink wrap (\x1b]8;;url\x1b\)
  • Prose-with-CSI preservation (the CSI sequences themselves survive, only token bodies are masked)
  • Colored prose-only no-op (no false positives)
  • Regression: bare-ESC / newline / ZWSP splits still mask

All 12 new tests pass; the 97 pre-existing test_redact.py tests continue to pass.

Files changed

  • agent/redact.py: 4-line regex addition, ~15-line function update
  • tests/agent/test_redact.py: new TestCSISplitTokens class with 12 cases

…Research#81012)

A vendor-prefix token wrapped in ANSI color codes (e.g. \x1b[32msk-…)
leaked ENTIRELY through redact_sensitive_text. The previous control-char
strip removed only the bare ESC byte, leaving the trailing [32m chars
intact — and the literal 'm' defeated _PREFIX_RE's (?<![A-Za-z0-9_-])
lookbehind on a prefix token that followed immediately after the
sequence.

Fix: compile _CSI_SEQUENCE_RE that matches the complete CSI leg of
ECMA-48 (parameter / intermediate / final byte ranges, including the
'?' private-mode prefix), strip CSI sequences as a unit before the
control-char pass, and treat CSI-internal bytes as collapsible in the
span validation so the join doesn't get rejected when a CSI sequence
sits inside the matched token span.

Reuses the CSI leg of tools/ansi_strip.py so the two scrubbers cannot
drift.

Regression tests cover the leak shapes from the issue: CSI directly
glued to sk-, CSI after the prefix, bold + color SGR, 256-color SGR,
true-color SGR, DEC private-mode CSI, OSC hyperlink wrap, ghp_ prefix,
prose preservation across CSI, and a colored prose-only no-op case.

Fixes NousResearch#81012
@Enough1122

Copy link
Copy Markdown
Contributor Author

Duplicate of #81060 (same issue #, opened earlier). Closing in favor of the earlier PR to avoid double-fixing the same issue.

@Enough1122 Enough1122 closed this Aug 7, 2026
@alt-glitch alt-glitch added type/security Security vulnerability or hardening comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data duplicate This issue or pull request already exists labels Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

redact: complete CSI/SGR sequences defeat prefix masking (ESC-byte-only stripping leaves 'm'-glue)

2 participants