CVE-2024-9393
Overview
Background
- `PdfStreamConverter`
- A Firefox stream converter that intercepts
application/pdfresponses and hands them to the built-in PDF.js viewer running under the privilegedresource://pdf.jsorigin. - `nsIStreamConverter`
- The XPCOM interface whose
getConvertedType/convertmethods let a component transform a channel’s payload from one MIME type into another before it reaches the document. - `nsIMultiPartChannel`
- A channel interface implemented for
multipart/x-mixed-replaceresponses, where a single HTTP response delivers a sequence of independent parts, each surfaced as its own sub-channel. - Site Isolation
- The desktop process-separation feature that confines documents to a process keyed by site, limiting (but not fully preventing) cross-origin data access.
Root Cause Analysis
The vulnerable code path was PdfStreamConverter.prototype.getConvertedType, which selected the PDF.js viewer for a response without accounting for the case where the underlying channel was an nsIMultiPartChannel. When a server returned a multipart/x-mixed-replace response containing a PDF part, the stream converter would still route the multipart channel to the PDF.js viewer, and the viewer document ended up loaded under the privileged resource://pdf.js origin while an attacker retained influence over subsequent parts of the same channel. This violated the invariant that only a single, well-formed PDF response should be promoted into the resource://pdf.js viewer context, allowing attacker-controlled content to run script in that privileged origin and read cross-origin PDF data.
The fix adds an explicit type check at the top of getConvertedType: if aChannel instanceof Ci.nsIMultiPartChannel, it throws Components.Exception with Cr.NS_ERROR_NOT_IMPLEMENTED, refusing to convert multipart responses at all. Because PDF.js was never designed to handle the sequential-replacement semantics of multipart channels, rejecting them outright removes the confused-deputy behavior rather than trying to sanitize each part.
getConvertedType trusted the response MIME type alone and ignored the multipart nature of the channel, letting a multipart/x-mixed-replace response smuggle content into the privileged resource://pdf.js viewer. The fix closes this by detecting nsIMultiPartChannel and refusing conversion, so multipart responses can never reach the PDF.js origin.Attack Path
- Serve a crafted multipart response
The attacker hosts a URL that returns a
multipart/x-mixed-replaceresponse whose part(s) are typed asapplication/pdf. - Trigger PDF stream conversion
The victim navigates to or embeds the URL, and Firefox invokes
PdfStreamConverter.getConvertedType, which selects the PDF.js viewer despite the channel being annsIMultiPartChannel. - Load the viewer under `resource://pdf.js` The multipart channel is promoted into the privileged PDF.js document context, where the attacker’s controlled part content is treated as viewer content.
- Execute script in the privileged origin
The crafted content runs arbitrary JavaScript under the
resource://pdf.jsorigin, escaping the attacker’s own origin restrictions. - Read cross-origin PDF content Using the elevated origin, the script accesses PDF content from other origins, fully cross-origin on Android and limited to same-site documents by Site Isolation on desktop.
Impact Assessment
resource://pdf.js origin, enabling theft of cross-origin PDF content. On desktop this is constrained to “same site” documents by Site Isolation, while on Android full cross-origin access is possible. The only precondition is that the victim loads an attacker-controlled URL that returns a specially crafted multipart/x-mixed-replace response.Changed Functions
| Function | Change | Notes |
|---|---|---|
getConvertedTypetoolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs |
modified | |
iftoolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs |
modified |
Files Changed
toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs
Audit Directions
- Type-based dispatch that ignores channel capabilitiesReview other
nsIStreamConverterand content-handler implementations that select a privileged viewer based solely on MIME type without checking whether the channel is multipart or otherwise streams attacker-controllable follow-up data. - Privileged `resource://` origins reachable from web contentAudit any code that promotes a network response into a
resource://orchrome://document context, ensuring the response shape and origin are validated before the elevation. - Multipart response handlingSearch for components that consume
multipart/x-mixed-replacestreams and confirm each part is re-validated, since later parts can differ from the first and subvert one-time trust decisions.
Patch
diff --git a/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs b/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs
index 2c85c1ae25d..bf64528d51f 100644
--- a/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs
+++ b/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs
@@ -1018,6 +1018,13 @@ PdfStreamConverter.prototype = {
},
getConvertedType(aFromType, aChannel) {
+ if (aChannel instanceof Ci.nsIMultiPartChannel) {
+ throw new Components.Exception(
+ "PDF.js doesn't support multipart responses.",
+ Cr.NS_ERROR_NOT_IMPLEMENTED
+ );
+ }
+
const HTML = "text/html";
let channelURI = aChannel?.URI;
// We can be invoked for application/octet-stream; check if we want the