fix(agents): detect C1 control characters in hasControlCharacter#103379
fix(agents): detect C1 control characters in hasControlCharacter#103379lsr911 wants to merge 2 commits into
Conversation
hasControlCharacter() checked for C0 control characters (0x00-0x1f) and DEL (0x7f) but did not check for C1 controls (0x80-0x9f). The C1 range includes the CSI introducer (0x9b) and other control codes that should not appear in user-facing error text. Add the C1 range to the check. Same pattern as the C1 fixes in sanitizeForConsole (openclaw#103226) and renderTerminalBufferText (openclaw#103274). Co-Authored-By: Claude <[email protected]>
|
Codex review: needs real behavior proof before merge. Reviewed July 11, 2026, 4:12 AM ET / 08:12 UTC. Summary PR surface: Source 0, Tests +15. Total +15 across 2 files. Reproducibility: yes. Current main deterministically accepts U+009B in Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Keep the narrow C1 rejection and regression test, then add redacted terminal, copied live output, or logs from the fallback path proving unsafe-hint suppression and normal-provider rendering. Do we have a high-confidence way to reproduce the issue? Yes. Current main deterministically accepts U+009B in Is this the best way to solve the issue? Yes. Extending the existing private fail-closed predicate is the narrowest maintainable fix and avoids changing unrelated text-sanitization contracts. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 81ce206ee84f. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source 0, Tests +15. Total +15 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
Add a focused regression case asserting that a provider id containing any C1 byte (0x80-0x9f), including the U+009B CSI introducer, is rejected so no reauthentication command with an embedded C1 escape is rendered, while a clean provider id still produces the expected command. Signed-off-by: lsr911 <[email protected]>
|
Superseded by #104362 — a single sink-wide C1 (0x80–0x9f) pass that folds this sink's fix in with a valid U+009B regression, alongside an audit of every other control-character sink (already-covered / deferred / out-of-scope). This consolidates the isolated C1 PRs per the direction on #103226. Closing in favor of the consolidated review. |
…g sinks Terminal-control sanitizers guard untrusted text before it reaches a terminal or log (CWE-117). The canonical range is C0 (0x00-0x1f), DEL (0x7f), and C1 (0x80-0x9f) - the range already used by the shared sanitizeForLog and by renderTerminalBufferText (openclaw#103274). C1 includes the 8-bit CSI introducer U+009B. Deliberate sink-wide pass: closes the C1 gap in twelve terminal/log output sinks, each keeping its own strip/escape/replace/truncate/reject action and gaining a focused valid-U+009B regression test. The PR body audits every other control-char sink (already-covered, deferred, or out-of-scope). Consolidates the isolated PRs openclaw#103379 openclaw#103380 openclaw#103381 openclaw#103382 openclaw#103383 openclaw#103402 Signed-off-by: lsr911 <[email protected]> openclaw#103405 and re-lands the sanitizeForConsole fix from openclaw#103226 cleanly.
What Problem This Solves
buildProviderReauthCommand()insrc/agents/failover-error.tsbuilds the copy-pasteable operator command shown in a failover remediation hint (Re-authenticate with: openclaw models auth login --provider '<provider>' --force). Before rendering, it rejects provider ids that contain control characters viahasControlCharacter().That guard only covered the C0 range (0x00-0x1f) and DEL (0x7f); it did not cover the C1 control range (0x80-0x9f). The C1 range includes the CSI introducer U+009B, an alternative ANSI escape prefix equivalent to
ESC [. A provider id carrying a C1 byte therefore passed the guard and was rendered inside the reauthentication command string, so the C1 escape could reach a terminal that later prints/copies that remediation hint.Change
Extend
hasControlCharacter()to also flag 0x80-0x9f:When the provider id contains any C1 byte,
buildProviderReauthCommandnow returnsundefined(no command rendered), matching the existing behavior for C0/DEL. Same C1 completion as #103226 (sanitizeForConsole) and #103274 (renderTerminalBufferText).Testing / Proof
Extended the existing
buildProviderReauthCommandcoverage insrc/agents/failover-error.test.tswith a focused C1 case: a provider id containing U+009B (and every byte across 0x80-0x9f) yieldsundefined, while a clean provider id still renders the expected command.The test calls the real exported
buildProviderReauthCommand, so the passing run is the before/after proof: on currentmainbuildProviderReauthCommand("anthropic" + U+009B + "[2J")renders a command with the raw C1 byte embedded in the shell literal; with this change it returnsundefined.