fix(security): neutralize CR/LF in rendered log records (CWE-117 formatter gap) - #1255
fix(security): neutralize CR/LF in rendered log records (CWE-117 formatter gap)#1255groupthinking wants to merge 1 commit into
Conversation
🔍 PR Validation✅ Current validation passed. |
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
Agent Completion Truth Gate: BLOCKEDReasons: Machine-readable verdict{
"details": {
"invalid_fields": [
"policy.agent_login",
"policy.run_id"
]
},
"reasons": [
"invalid_payload"
],
"verdict": "blocked"
} |
|
@coderabbitai review Truth-gate disposition (unattended remediation run)The Code-level checks are green on head
What I corrected this run:
What remains blocked — and requires a human, by design:
Staged next command for a maintainer, once chartered: Generated by Claude Code |
|
✅ Action performedReview finished.
|
StructuredFormatter returned the base-formatted string verbatim, so any CR/LF carried by user-controlled data or by raw exception text appended via exc_info / logger.exception could forge or split log lines. Inline message sanitization (e.g. the _safe_log work on PR #810's router) does not reach the exc_info traceback or structured `extra` fields, leaving a log-injection vector on the fully rendered record. Escape CR/LF and other line separators in the single central sink - StructuredFormatter.format() - so every logger call (message, extra, and exc_info traceback) is covered at once, even when a call site forgets to sanitize its inputs. Escaping (not dropping) keeps the original content visible and greppable while preventing it from starting a new line. Complements #810 (#913, #898): that PR hardens message interpolation in the v1 router; this closes the formatter-level gap Copilot flagged there, which lives outside #810's router.py scope. Adds tests/unit/test_logging_config_crlf.py asserting rendered handler output (not a helper's return value) across the message, exc_info, logger.exception+extra, and full control-char vectors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BQcuj14cL5gGjdy2Rb925v
9fb4a8a to
4ed812e
Compare
The CWE-117 formatter hardening merged via #1270 (now on main) covers the str.splitlines() boundary set + ESC/FS/GS/RS but omits NUL (0x00). The only cluster PR that carried NUL, #1255, was closed during consolidation without the codepoint being carried over — so main's StructuredFormatter lets a raw NUL reach the sink, where a C-based log shipper can truncate the record. Add ord("\x00"): "\\u0000" to _UNSAFE_LOG_CHARS (the exact fix the cluster consolidation analysis on #1270 specified) so NUL is escaped to a JSON-valid, reversible sequence like the other separators. Adds a focused regression test; the existing table-driven tests auto-extend to cover it. Focused suite: 10 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSFzJYm5bYMuoAo9ssoiAM
…1270/#1255) (#1422) fix(security): neutralize NUL (0x00) in log records (CWE-117 gap) The CWE-117 formatter hardening merged via #1270 (now on main) covers the str.splitlines() boundary set + ESC/FS/GS/RS but omits NUL (0x00). The only cluster PR that carried NUL, #1255, was closed during consolidation without the codepoint being carried over — so main's StructuredFormatter lets a raw NUL reach the sink, where a C-based log shipper can truncate the record. Add ord("\x00"): "\\u0000" to _UNSAFE_LOG_CHARS (the exact fix the cluster consolidation analysis on #1270 specified) so NUL is escaped to a JSON-valid, reversible sequence like the other separators. Adds a focused regression test; the existing table-driven tests auto-extend to cover it. Focused suite: 10 passed. Claude-Session: https://claude.ai/code/session_01GSFzJYm5bYMuoAo9ssoiAM Co-authored-by: Claude <noreply@anthropic.com>
Canonical issue
Related to (not implementing) #913 / #898. #913 is the canonical issue for #810's router-level
_safe_logwork; this PR is complementary and closes the formatter-level CWE-117 gap Copilot flagged on #810, which lives outsiderouter.py. It does not fulfil #913's file contract, so it should not be scored against it. This work needs its own human-chartered canonical issue (see Agent provenance).Outcome
StructuredFormatterreturned the base-formatted string verbatim, so any CR/LF carried by user-controlled data or by raw exception text appended viaexc_info/logger.exceptioncould forge or split log lines. Inline message sanitization (e.g. the_safe_logwork on #810's router) never reaches theexc_infotraceback or structuredextrafields, leaving a log-injection vector on the fully rendered record.This escapes CR/LF and other line separators in the single central sink —
StructuredFormatter.format()— so every logger call (message,extra, andexc_infotraceback) is neutralized at once, even when a call site forgets to sanitize its inputs. Escaping (not dropping) keeps the original content visible and greppable while preventing it from starting a new physical line.Scope
Single concern — two files only:
src/youtube_extension/backend/config/logging_config.py— add_UNSAFE_LOG_CHARStable;format()now.translate()s the final rendered record.tests/unit/test_logging_config_crlf.py— new regression suite asserting rendered handler output (message,exc_info,logger.exception+extra, and full control-char coverage).Explicitly excluded:
router.pymessage interpolation (owned by #810); no sharedlogsafemodule is introduced (none exists onmain— the fix is self-contained).Risk
\nseparators — a deliberate CWE-117-safe trade-off (one physical line per record). Ordinary single-line messages are byte-for-byte unchanged (test_ordinary_message_is_unchanged).format()change; no schema, API, or data migration involved.Verification
Tied to head
4ed812ee4aea4b79ea26604b9e21adb6fa58ac37:tests/unit/test_logging_config_crlf.py: 15 passed (PYTHONPATH=src pytest ... -o addopts="").CRITICAL - FORGED ADMIN LINEon its own line; patched formatter → 1 physical line, payload inline and escaped.ruff checkclean on both changed files.agent-completion/truth-gate— BLOCKED, human-gated (see below).Production evidence
Backend Python change; alters only the textual representation of log records, not request values or behavior. The Next.js
apps/webVercel preview does not exercise this Python path.Agent handoff
agent-completion/truth-gategreen — cannot be satisfied autonomouslymainAgent provenance
This PR is intentionally not accompanied by a fabricated
agent-lock-manifest. The truth-gate requires a canonical issue with a frozen pre-dispatch intent snapshot and a trusted terminal agent-result; those are pre-dispatch governance artifacts a post-hoc autonomous run cannot honestly manufacture without impersonating the gate. Per the guidance on #810 ("do not weaken or impersonate the gate"), the manifest is left for a human to charter — hence the gate'sinvalid_payload. The code-level evidence above stands on its own.🤖 Generated with Claude Code
https://claude.ai/code/session_01BQcuj14cL5gGjdy2Rb925v