CVE-2025-43392
Overview
Background
- Origin-clean flag / canvas taint
- A canvas becomes tainted (origin-clean=false) when it draws cross-origin pixels, which blocks pixel read-back (toDataURL/getImageData).
- OffscreenCanvas placeholder
- An OffscreenCanvas transferred from a canvas commits its rendered frames back to a visible placeholder HTMLCanvasElement.
- setPlaceholderBuffer pipeline
- The path (source -> main thread -> placeholder) that hands the rendered ImageBuffer to the visible canvas.
- Same-origin policy for canvas
- Reading pixels from a tainted canvas is forbidden to prevent cross-origin image exfiltration.
Root Cause Analysis
An OffscreenCanvas can draw a cross-origin image (which taints the canvas, clearing its origin-clean flag) and then transfer its rendered bitmap to a visible placeholder HTMLCanvasElement via commitToPlaceholderCanvas / PlaceholderRenderingContextSource::setPlaceholderBuffer.
Pre-patch, that transfer carried the bitmap and its opaque flag but NOT the origin-clean/tainted status: setPlaceholderBuffer took only (ImageBuffer&, bool opaque), so the output placeholder canvas was left origin-clean even though the pixels came from a tainted OffscreenCanvas. With the destination canvas wrongly considered origin-clean, script could call toDataURL()/getImageData()/toBlob() on it and read back the cross-origin image pixels – a same-origin-policy bypass that exfiltrates cross-origin image data.
The fix threads an originClean boolean through the whole placeholder pipeline (OffscreenCanvas::commitToPlaceholderCanvas passes m_context->canvasBase().originClean(); PlaceholderRenderingContextSource::setPlaceholderBuffer and PlaceholderRenderingContext::setPlaceholderBuffer take and forward it), and the output side applies it: if (originClean) canvasBase().setOriginClean(); else canvasBase().setOriginTainted();.
The restored invariant is that the origin-clean taint of the OffscreenCanvas is preserved when its bitmap is committed to the placeholder canvas, so a tainted source keeps the destination tainted and read-back is blocked.
Attack Path
- Taint an OffscreenCanvas Draw a cross-origin image (no CORS) into an OffscreenCanvas, clearing its origin-clean flag (canvas becomes tainted).
- Commit to a placeholder canvas Transfer control / commit the OffscreenCanvas bitmap to a visible HTMLCanvasElement via the placeholder rendering context.
- Lose the taint Pre-patch, setPlaceholderBuffer did not carry originClean, so the destination canvas is treated as origin-clean despite holding cross-origin pixels.
- Read back cross-origin pixels Call toDataURL()/getImageData() on the destination canvas to exfiltrate the cross-origin image data – an SOP bypass.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
OffscreenCanvas::commitToPlaceholderCanvasSource/WebCore/html/OffscreenCanvas.cpp |
modified | Passes m_context->canvasBase().originClean() into setPlaceholderBuffer so the taint travels with the bitmap. |
PlaceholderRenderingContextSource::setPlaceholderBufferSource/WebCore/html/canvas/PlaceholderRenderingContext.cpp |
modified | Gains an originClean parameter and captures/forwards it through the callOnMainThread hop to the placeholder. |
PlaceholderRenderingContext::setPlaceholderBufferSource/WebCore/html/canvas/PlaceholderRenderingContext.cpp |
modified | Applies the flag to the destination: canvasBase().setOriginClean() or setOriginTainted(). |
PlaceholderRenderingContext(.h) setPlaceholderBuffer declsSource/WebCore/html/canvas/PlaceholderRenderingContext.h |
modified | Signatures updated to carry originClean end-to-end. |
Files Changed
LayoutTests/http/tests/security/offscreen-canvas-remote-read-remote-image-expected.txtLayoutTests/http/tests/security/offscreen-canvas-remote-read-remote-image.htmlSource/WebCore/html/OffscreenCanvas.cppSource/WebCore/html/canvas/PlaceholderRenderingContext.cppSource/WebCore/html/canvas/PlaceholderRenderingContext.h
Audit Directions
- Other bitmap transfersAudit canvas/ImageBitmap transfer paths (transferToImageBitmap, drawImage from canvas, VideoFrame) to ensure origin-clean/taint travels with pixel data.
- Placeholder pipeline flagsReview what metadata setPlaceholderBuffer carries (opaque, originClean) for any other security-relevant flag dropped across the main-thread hop.
- setOriginClean/Tainted callersgrep for setOriginClean()/setOriginTainted() to confirm every path that copies external pixels into a canvas sets taint correctly.