Skip to content

Sanitize ANSI escape sequences in CSP report logging - #1397

Merged
richard-to merged 1 commit into
mainfrom
claude/pr-1396-review-x21s9w
Aug 1, 2026
Merged

Sanitize ANSI escape sequences in CSP report logging#1397
richard-to merged 1 commit into
mainfrom
claude/pr-1396-review-x21s9w

Conversation

@richard-to

Copy link
Copy Markdown
Collaborator

Summary

The /__csp__ endpoint logs attacker-controlled CSP report fields directly via print(). Unsanitized ANSI/VT100 escape sequences in those fields are interpreted by ANSI-compatible terminals, allowing a malicious CSP report to manipulate the developer's terminal output (e.g. hidden/spoofed text, cursor manipulation, OSC-based tricks like fake window titles or hyperlinks).

This adapts and fixes up #1396 (thanks to @5H4D0WBY73 for the original report and PR — opening as a new PR with their OK since #1396 had a couple of issues that needed addressing).

Changes

  • Added _sanitize_terminal() to mesop/server/static_file_serving.py, which strips ANSI CSI/OSC/DCS/APC/PM/SOS escape sequences from a value before logging.
  • Applied it to the untrusted document-uri, blocked-uri, and violated-directive fields in csp_report() before they're printed.
  • Preserves existing logging behavior/formatting for normal input (the app's own tc.* terminal color codes are untouched, since sanitization is only applied to the untrusted report fields, not the log template itself).

Fixes vs. #1396

  • Bug fix: Sanitize ANSI escape sequences in CSP report logging #1396 deleted the path = urlparse(document_uri).path assignment without replacement, while path is still referenced later in the log output — every call to csp_report() would raise NameError and return a 500. This PR restores path (derived from the already-sanitized document_uri).
  • Formatting: matches the project's 2-space indent (ruff format clean; pyproject.toml sets indent-width = 2).
  • Type annotations: kept the original : str annotations on document_uri, blocked_uri, violated_directive.

Test plan

  • _sanitize_terminal() unit tests: CSI stripping, OSC stripping, plain text passthrough, non-str coercion.
  • New endpoint-level test (test_csp_report_sanitizes_ansi_escapes_in_output) that POSTs a crafted CSP report with embedded escape sequences to /__csp__ via a Flask test client and asserts: a 204 response (catching the regression above, which would surface as a 500), the malicious escape sequences are stripped from the printed output, and the surrounding plain text is preserved.
  • Ran the full static_file_serving_test.py suite locally — all 8 tests pass.
  • ruff format --diff and ruff check show no new issues introduced by this change.

Generated by Claude Code

The /__csp__ endpoint logs attacker-controlled CSP report fields
directly via print(), so unsanitized ANSI/VT100 escape sequences in
those fields were interpreted by ANSI-compatible terminals. Strip
escape sequences from document-uri, blocked-uri, and violated-directive
before logging.

Adapted from #1396, which introduced a NameError (the `path` variable
used later in the log output was deleted without replacement) and had
formatting inconsistent with the project's 2-space indent convention.
Restores `path`, keeps type annotations, and adds an endpoint-level
test that exercises /__csp__ directly so a similar regression would be
caught in CI.
@richard-to
richard-to merged commit f38c42a into main Aug 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants