Skip to content

fix: prevent D3 export action XSS via untrusted dataUrl#1344

Merged
Soare-Robert-Daniel merged 3 commits into
developmentfrom
fix/d3-print-action-xss
Jul 16, 2026
Merged

fix: prevent D3 export action XSS via untrusted dataUrl#1344
Soare-Robert-Daniel merged 3 commits into
developmentfrom
fix/d3-print-action-xss

Conversation

@Soare-Robert-Daniel

@Soare-Robert-Daniel Soare-Robert-Daniel commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

The D3 renderer's print action wrote the dataUrl received over postMessage from the null-origin export iframe into a popup via document.write(), letting a hostile value smuggle markup/script into a same-origin document. The value is now validated as a base64 data:image/(png|jpeg|webp) URI and the <img> is built via the DOM API so it is only ever an attribute value.

Follow-up hardening for the same value on the PHP side: sanitizeSettings() only stores chart-img when it is a base64 image data URI, and save_chart_image() verifies the PNG magic bytes before writing to uploads. The bogus baselined @return attachment type on save_chart_image() was corrected to int and its three stale PHPStan baseline entries removed.

Will affect visual aspect of the product

NO

Test instructions

  • npx jest classes/Visualizer/D3Renderer/tests/print-action-xss.test.js — hostile dataUrl payloads open no popup and inject no markup; a legitimate PNG export renders as a single <img>.
  • vendor/bin/phpunit --filter Test_Visualizer_Sanitize_Settings — hostile chart-img values are dropped; save_chart_image() rejects non-PNG payloads.
  • Manually: edit a chart, use the print/download-PNG export actions and confirm they still work.

Check before Pull Request is ready:

🤖 Generated with Claude Code

Soare-Robert-Daniel and others added 2 commits July 16, 2026 12:10
The D3 chart runs in a null-origin sandboxed iframe and returns its
exported image over postMessage, so the dataUrl is attacker-controlled.
The print action wrote it unescaped into a same-origin window.open()
popup via document.write, letting hostile chart code inject active
markup into the site origin (stored XSS reachable by a Contributor who
can edit their own draft chart, no unfiltered_html needed).

Validate the value as a base64 image data URI and build the <img> via
the DOM API instead of string concatenation. Adds a jsdom regression
test driving the real module (red against the old code, green now).

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pirate-bot

Copy link
Copy Markdown
Contributor

💂‍♂️ PR Error! No Linked Issue found. Please link an issue or mention it in the body using #<issue_id>

@pirate-bot

pirate-bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Plugin build for e369e5a is ready 🛎️!

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pirate-bot pirate-bot added the pr-checklist-complete The Pull Request checklist is complete. (automatic label) label Jul 16, 2026
@Soare-Robert-Daniel
Soare-Robert-Daniel merged commit fd96ea1 into development Jul 16, 2026
10 of 13 checks passed
@Soare-Robert-Daniel
Soare-Robert-Daniel deleted the fix/d3-print-action-xss branch July 16, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-complete The Pull Request checklist is complete. (automatic label)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants