Skip to content

fix(security): sanitize color params and escape title to stop SVG/HTML injection - #4

Merged
chicks-net merged 2 commits into
deployfrom
fix/xss-svg-injection
Aug 30, 2026
Merged

chicks-net merged 2 commits into
deployfrom
fix/xss-svg-injection

Conversation

@chicks-net

Copy link
Copy Markdown
Member

Summary

/graph interpolated custom_title and every *_color query param directly into the generated SVG — a <style> block, fill/stroke attributes, and a <foreignObject><h1> title — with no validation or escaping.

A crafted color/bg_color/border_color/title_color/line/point/area_color or custom_title value can break out of its context and inject a <script> tag. Since the response is served as image/svg+xml with no CSP, that script executes when the URL is navigated to directly or embedded via <object>/<iframe>.

Verified with a PoC before this fix — e.g. color=fff} </style><script>alert(document.domain)</script><style>{ or custom_title=</h1><script>alert(1)</script> — the raw <script> tag survived unmodified in the response body.

Not previously reported anywhere I could find (no advisory on this repo, the upstream repo, or the fork). The sibling project this one is modeled after, github-readme-stats, had a similar bug class (CVE-2020-23986, fixed in PR #255).

Changes

  • src/utils.ts: whitelist all color query params to hex-digit-only (sanitizeColor), falling back to the theme default on anything else. HTML-escape the resolved title (escapeHtml) before it reaches the SVG template.
  • src/utils.ts / src/handlers.ts: add Content-Security-Policy: script-src 'none'; sandbox on SVG responses as defense in depth, so a future injection bug can't execute script even if it slips past validation.
  • __test__/utils.test.ts: regression tests covering malicious color params (fall back to theme default) and a malicious custom_title (HTML-escaped, no raw <script> in output).

Test plan

  • npx tsc --noEmit — clean
  • npx jest — all tests pass except one pre-existing network-dependent test that needs a real GitHub TOKEN (fails identically on the base branch, unrelated to this change)
  • Manual PoC re-run against the patched code confirms no raw <script> survives and malicious colors fall back to theme defaults

🤖 Generated with Claude Code

…L injection

The /graph endpoint interpolated custom_title and all *_color query
params directly into the generated SVG (a <style> block, fill/stroke
attributes, and a <foreignObject><h1> title) with no validation or
escaping. A crafted custom_title or color value could break out and
inject a <script> tag, which executes since the response is served as
image/svg+xml with no CSP when the URL is navigated to directly or
embedded via <object>/<iframe>.

Verified with a PoC (payloads like `color=fff} </style><script>...`
and `custom_title=</h1><script>...`) that the raw <script> tag
survived unmodified before this change.

- Whitelist color query params to hex-digit-only before use, falling
  back to the theme default otherwise.
- HTML-escape the resolved title before it reaches the SVG template.
- Add a Content-Security-Policy: script-src 'none'; sandbox header on
  SVG responses as defense in depth.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 30, 2026 21:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the /graph SVG output against injection by sanitizing user-controlled color query parameters, escaping the rendered title, and adding a restrictive CSP header as defense in depth.

Changes:

  • Add sanitizeColor (hex-only) for all color query params and apply theme-default fallbacks.
  • HTML-escape the resolved graph title before embedding it into the SVG <foreignObject>.
  • Add Content-Security-Policy: script-src 'none'; sandbox for SVG responses and add regression tests for sanitization/escaping.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/utils.ts Adds color sanitization, title escaping, and sets CSP header on SVG responses.
src/handlers.ts Adds CSP header on the error SVG response path.
__test__/utils.test.ts Adds regression tests for malicious color params and custom_title escaping.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/utils.ts Outdated
Comment thread src/utils.ts
- Restrict HEX_COLOR to the lengths CSS/SVG actually accept (3, 4, 6,
  8) instead of any 1-8 digit run, so an accepted-but-invalid length
  (e.g. 1, 2, 5, 7 digits) can no longer render as a broken color.
- Assert the Content-Security-Policy header is present on both the
  success and error /graph route tests, not just Content-Type and
  Cache-Control.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@chicks-net
chicks-net merged commit 9336e06 into deploy Aug 30, 2026
2 checks passed
@chicks-net
chicks-net deleted the fix/xss-svg-injection branch August 30, 2026 21:34
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