Skip to content

🤖 fix: harden renderer HTML sinks against XSS#2502

Merged
ibetitsmike merged 4 commits into
mainfrom
mike/hunk-viewer-xss-hardening
Feb 20, 2026
Merged

🤖 fix: harden renderer HTML sinks against XSS#2502
ibetitsmike merged 4 commits into
mainfrom
mike/hunk-viewer-xss-hardening

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix renderer XSS exposure in diff and markdown diagram paths by removing unsafe filename HTML rendering in HunkViewer and hardening Mermaid SVG insertion.

Background

A filename from workspace/repository content was being transformed into HTML and injected via dangerouslySetInnerHTML in HunkViewer. Because filenames are attacker-controlled, this enabled immediate XSS when viewing a crafted diff. Given renderer-accessible privileged surfaces, that XSS materially increased impact.

Implementation

  • Replaced filename highlight HTML strings in HunkViewer with safe React element rendering (<mark> nodes) so React escaping remains in effect.
  • Removed dangerouslySetInnerHTML usage for hunk.filePath display.
  • Hardened Mermaid rendering:
    • switched Mermaid config from securityLevel: "loose" to "strict"
    • added sanitizeMermaidSvg() and route all rendered SVG through it before innerHTML assignment
    • removed active containers (script, iframe, object, embed) and stripped inline event handlers / dangerous URL schemes from URL-bearing attributes
    • canonicalized encoded URL values before scheme checks (decodes entity/percent encodings and strips control/whitespace obfuscation) so payloads like java&#10;script: are blocked
    • guarded numeric entity decoding against invalid Unicode code points so crafted values cannot throw during sanitization
    • preserved <foreignObject> nodes so Mermaid wrapped labels continue to render
  • Added explicit SECURITY AUDIT comments at unavoidable HTML sinks to document trust boundaries.
  • Added Mermaid.sanitization.test.ts to verify malformed SVG rejection, active-content stripping, encoded-scheme blocking, invalid-entity handling, and label preservation.
  • Added a new Security: Renderer HTML & XSS section in docs/AGENTS.md to codify safe patterns.

Validation

  • make static-check (before initial push)
  • bun test src/browser/components/Messages/Mermaid.sanitization.test.ts
  • make static-check (after foreignObject-label follow-up)
  • bun test src/browser/components/Messages/Mermaid.sanitization.test.ts
  • make static-check (after encoded-scheme canonicalization follow-up)
  • bun test src/browser/components/Messages/Mermaid.sanitization.test.ts
  • make static-check (after invalid-entity guard follow-up)

Risks

  • Mermaid securityLevel: "strict" may reduce support for some diagram features that relied on looser behavior (especially scriptable/unsafe links), but this is intentional hardening.
  • Sanitization is defense-in-depth; if Mermaid output format changes significantly, sanitizer assumptions should be revisited.

Generated with mux • Model: openai:gpt-5.3-codex • Thinking: xhigh • Cost: $0.01

Replace attacker-controlled filename HTML rendering with safe React nodes, harden Mermaid SVG rendering with strict mode + sanitization, and document renderer XSS guardrails in AGENTS.

---

_Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: `$0.01`_

<!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.01 -->
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cd4c8ba43

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/browser/components/Messages/Mermaid.tsx Outdated
Keep Mermaid label rendering intact by preserving foreignObject nodes while continuing to strip active content and dangerous URL schemes.

---

_Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: `$0.01`_

<!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.01 -->
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

Addressed the foreignObject regression concern by preserving label nodes while stripping active content and unsafe URL schemes.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a26607d76

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/browser/components/Messages/Mermaid.tsx Outdated
Decode encoded URL forms before blocked-scheme checks so obfuscated payloads like `java&#10;script:` and `java%0Ascript:` are stripped during Mermaid SVG sanitization.

---

_Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: `$0.01`_

<!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.01 -->
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

Addressed encoded/obfuscated scheme bypasses by canonicalizing entity + percent-encoded URL values before blocked-scheme checks.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 442e5e4b53

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/browser/components/Messages/Mermaid.tsx Outdated
Guard numeric entity decoding against invalid Unicode code points so sanitizer canonicalization cannot throw on crafted values.

---

_Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: `$0.01`_

<!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.01 -->
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

Added invalid-codepoint guards in entity decoding so sanitizer canonicalization cannot throw on crafted numeric entities.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ibetitsmike ibetitsmike added this pull request to the merge queue Feb 20, 2026
Merged via the queue into main with commit 7482449 Feb 20, 2026
23 checks passed
@ibetitsmike ibetitsmike deleted the mike/hunk-viewer-xss-hardening branch February 20, 2026 01:16
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.

1 participant