Skip to content

fix(security): neutralize CR/LF in rendered log records (CWE-117 formatter gap) - #1255

Closed
groupthinking wants to merge 1 commit into
mainfrom
claude/determined-maxwell-ef6pqu
Closed

fix(security): neutralize CR/LF in rendered log records (CWE-117 formatter gap)#1255
groupthinking wants to merge 1 commit into
mainfrom
claude/determined-maxwell-ef6pqu

Conversation

@groupthinking

@groupthinking groupthinking commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Canonical issue

Related to (not implementing) #913 / #898. #913 is the canonical issue for #810's router-level _safe_log work; this PR is complementary and closes the formatter-level CWE-117 gap Copilot flagged on #810, which lives outside router.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

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 #810's router) never reaches the exc_info traceback or structured extra fields, 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, and exc_info traceback) 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_CHARS table; 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.py message interpolation (owned by #810); no shared logsafe module is introduced (none exists on main — the fix is self-contained).

Note: an earlier revision of this branch also carried three code_generator.py scaffold-cleanup commits. Those are the canonical content of PR #1252 (closes #1253), so they were rebased out of this branch (head is now 4ed812e) — no work was discarded, and this PR is now a focused single-concern security change.

Risk

  • Risk level: low
  • Failure mode: multi-line tracebacks now render as a single line with escaped \n separators — 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).
  • Rollback: revert the two-line format() change; no schema, API, or data migration involved.

Verification

Tied to head 4ed812ee4aea4b79ea26604b9e21adb6fa58ac37:

  • Focused tests — tests/unit/test_logging_config_crlf.py: 15 passed (PYTHONPATH=src pytest ... -o addopts="").
  • Before/after proof against rendered output: stock formatter → 5 physical lines, forged CRITICAL - FORGED ADMIN LINE on its own line; patched formatter → 1 physical line, payload inline and escaped.
  • ruff check clean on both changed files.
  • agent-completion/truth-gateBLOCKED, 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/web Vercel preview does not exercise this Python path.

Agent handoff

Agent 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's invalid_payload. The code-level evidence above stands on its own.


🤖 Generated with Claude Code

https://claude.ai/code/session_01BQcuj14cL5gGjdy2Rb925v

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

🔍 PR Validation

✅ Current validation passed.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • [‘architecture-gap’, ‘bug’, ‘ci-cd’, ‘ci/cd’, ‘copilot-rabbit’, ‘documentation’, ‘duplicate’, ‘enhancement’, ‘frontend’, ‘github_actions’, ‘good first issue’, ‘help wanted’, ‘high-priority’, ‘invalid’, ‘javascript’, ‘ml-model’, ‘needs-triage’, ‘pipeline-critical’, ‘placeholder-code’, ‘priority:high’, ‘python’, ‘python:uv’, ‘question’, ‘styling’, ‘tests’, ‘v0’]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 76bbd432-1b4b-4605-b43a-d23778156c37

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Ready Ready Preview, v0 Aug 2, 2026 5:58pm

@github-actions github-actions Bot added the python label Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 4ed812e.
Ensure 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 Files

None

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "invalid_fields": [
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Truth-gate disposition (unattended remediation run)

The agent-completion/truth-gate is red, and I am not turning it green autonomously — this is the correct, honest terminal state. Breakdown against the machine verdict:

Code-level checks are green on head 9fb4a8a:

  • tests/unit/test_logging_config_crlf.py15 passed (rendered-output regression: message, exc_info traceback, logger.exception+extra, full control-char set).
  • ruff check clean; Dependency Review ✅; Vercel preview Ready.

What I corrected this run:

What remains blocked — and requires a human, by design:

  1. missing_intent_snapshot — the gate needs a frozen pre-dispatch intent snapshot. I cannot manufacture one after the fact without impersonating the gate (per the explicit warning on fix(security): sanitize user-controlled values in API logs (CWE-117 log injection) #810).
  2. scope_drift (residual) — this branch also carries three pre-existing, unmerged code_generator.py scaffold-cleanup commits. Branch policy forbids discarding unmerged work, so an autonomous run cannot both keep them and match a single-issue file contract. A maintainer should decide whether to split them into their own PR.
  3. draft_pr + final human review — this is a security change to protected main; it stays draft pending sign-off. Un-drafting solely to pass the gate would be gaming it.

Staged next command for a maintainer, once chartered:

gh pr ready 1255 && gh pr merge 1255 --squash   # after canonical-issue charter + security review

Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

@groupthinking I will review the formatter change and the regression coverage. I will assess code behavior independently from the human-gated agent-completion/truth-gate status.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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
@groupthinking
groupthinking force-pushed the claude/determined-maxwell-ef6pqu branch from 9fb4a8a to 4ed812e Compare August 2, 2026 17:57
groupthinking pushed a commit that referenced this pull request Aug 7, 2026
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
groupthinking added a commit that referenced this pull request Aug 7, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cancelled video-to-software request leaks the scaffold temp directory

2 participants