# Plate: Media embed provider metadata can bypass URL sanitization and execute iframe JavaScript

Plate media embed trusted serialized provider metadata, skipping URL protocol validation, so a javascript: url rendered as an iframe src executed JS in the victim's browser.

- Payout: Research
- Severity: high
- Program: Plate
- Found by: DavidCarliez
- Disclosed: 2026-08-25
- CVE: CVE-2026-55596
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-qj6x-xx2h-8hvv
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-qj6x-xx2h-8hvv
- Tags: area:web domain:web impact:integrity kind:research platform:ghsa sev:high tech:nodejs tech:react technique:source-review vuln:xss

**Target:** @platejs/media MediaEmbedElement iframe renderer
**Root cause:** useMediaState had a fast path for serialized nodes containing provider or sourceUrl that returned stored url directly without calling parseMediaUrl, so the http/https protocol allowlist was skipped. MediaEmbedElement then rendered the unvalidated url as iframe src for non-YouTube providers.
**Steps:**
1. Load a Plate document containing a media_embed node with `"provider": "vimeo"`, `"sourceUrl": "https://vimeo.com/1"`, and `"url": "javascript:parent.postMessage('plate-media-xss','*')"`.
2. Render it with the registry `MediaEmbedElement`; the provider fast path returns the stored url unvalidated.
3. Component sees provider vimeo and renders `<iframe src={embed.url}>`, executing the javascript: payload.
4. Observe parent page receives `plate-media-xss`, confirming iframe JS execution.
**How found:** Noticed parseMediaUrl was the intended protocol-allowlist hardening point but useMediaState had a fast path for serialized nodes with provider/sourceUrl that bypassed it, then traced how MediaEmbedElement consumes embed.url as iframe src.
**Exploitation:** Attacker crafts or shares a Plate document with attacker-controlled provider and javascript: url; victim opens it in an app using the registry media embed component, and the iframe src executes JS in the victim's origin, exposing page data and allowing actions as the victim.
**Insight:** When a sanitizer exists at one entry point, look for alternate code paths (cached/serialized metadata fast paths) that return the same field without re-running it; derived metadata like provider/id in stored documents should be recomputed, not trusted.

