Medium CVSS 6.1 webkit Bypass 🔧 Commit mapped

Overview

Medium
Severity
6.1
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to a cross site scripting attack
ComponentWebCore Platform/Network
Bug ClassBypass
Tracker273805
Fix commitefaf5e842f10 (WebKit/WebKit)
CWECWE-79 (Cross-site scripting)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
CISA KEVNot listed
CreditedJohan Carlsson (joaxcar)
Disclosed2024-07-29

Background

MIME type downgrade (text/plain preference)
A defensive WebKit behavior that keeps a server-declared text/plain response inert instead of letting a sniffed/proposed scriptable type turn it into active content.
adjustMIMETypeIfNecessary
The iOS WebCore routine that rewrites a response’s MIME type based on helpers like shouldPreferTextPlainMIMEType before the content is dispatched to a parser.
XHTML / html-namespaced script
application/xhtml+xml is parsed as an XML document in which <script> elements in the XHTML namespace are executable, making XHTML a scriptable (active) content type.
X-Content-Type-Options: nosniff
A header telling the browser not to MIME-sniff; the test’s content-disposition variant shows the fix must hold even when sniffing is disabled and a type is proposed by other means.
Content sniffing / proposed MIME type
The platform network layer may compute a ‘proposed’ type from bytes or filename that differs from the server’s declared type, which is what could promote text/plain to XHTML.

Root Cause Analysis

On iOS, WebCore post-processes network responses in WebCoreURLResponseIOS.mm to defensively downgrade certain MIME types. The helper shouldPreferTextPlainMIMEType returns true when the server-declared type is text/plain and the platform/network layer proposed a scriptable markup type, in which case adjustMIMETypeIfNecessary keeps the response as text/plain so it is displayed inertly rather than parsed as active content. Before the patch the allow-list of ‘proposed’ types that should be forced back to text/plain covered text/xml, application/xml, and image/svg+xml but omitted application/xhtml+xml. XHTML is a scriptable document type: an XHTML document can carry executable html:script elements in the XHTML namespace, so if a response that a server labeled text/plain is instead treated as application/xhtml+xml, WebKit will parse it as an XHTML document and run its scripts. The invariant being enforced is ‘a resource the server declared as text/plain must not be silently reinterpreted as an executable/scriptable document’; the missing entry broke that invariant for the XHTML case, so content sniffing or a proposed-type computation could promote a text/plain body into an active XHTML document.

The fix adds application/xhtml+xml to the same list, so a text/plain response with a proposed XHTML type is coerced back to text/plain and its embedded scripts do not execute. The added layout tests confirm that xhtml-with-html.xhtml (and a Content-Disposition:inline + X-Content-Type-Options:nosniff variant) are reported as MIME type text/plain and that the embedded console.log(‘Fail’) script does not run.

Key insight
An incomplete allow-list: the text/plain-preference safeguard forced XML and SVG back to inert text/plain but forgot application/xhtml+xml, so a text/plain response could still be reinterpreted as scriptable XHTML and run its embedded scripts – classic XSS via MIME confusion, fixed by completing the list.

Attack Path

  1. Control a response body and its declared type The attacker gets a victim to load a resource whose bytes are attacker-controlled XHTML containing an html-namespaced html:script, e.g. an upload or user-content endpoint that serves files as text/plain.
  2. Induce an XHTML proposed type Arrange conditions (filename extension .xhtml, sniffing, or the network layer’s proposed MIME computation) so WebKit’s proposed type becomes application/xhtml+xml even though the server said text/plain.
  3. Slip past the text/plain downgrade Because application/xhtml+xml was absent from shouldPreferTextPlainMIMEType, adjustMIMETypeIfNecessary does not force text/plain, so the response is handed to the XML/XHTML document parser.
  4. Execute injected script The XHTML parser runs the embedded html:script, executing attacker JavaScript in the security context/origin the document is loaded under – a cross-site scripting outcome.
  5. Abuse the origin The script performs same-origin actions (read cookies/DOM, issue authenticated requests) against the origin serving the content.

Impact Assessment

This is a MIME-type handling / content-type confusion flaw, not a memory-safety bug: the primitive is the ability to get attacker-supplied bytes that a server marked text/plain parsed and scripted as XHTML, i.e. cross-site scripting within the loaded document’s origin. Realistic impact is script execution in that origin (cookie/DOM theft, authenticated requests, phishing), scoped to whatever origin serves the content and constrained by the same-origin policy; it does not by itself yield memory corruption or a sandbox escape. It executes in the WebContent process and is limited to iOS (the fix is in the ios/ platform file).

Changed Functions

FunctionChangeNotes
shouldPreferTextPlainMIMEType
Source/WebCore/platform/network/ios/WebCoreURLResponseIOS.mm
modified Adds application/xhtml+xml to the set of proposed MIME types that, when the declared type is text/plain, force the response back to text/plain -- closing the XHTML scripting gap alongside text/xml, application/xml, image/svg+xml.

Audit Directions

  • Complete the scriptable-type list
    Re-examine shouldPreferTextPlainMIMEType and any sibling allow-lists for other scriptable/active markup types that are missing – e.g. application/xml-external-parsed-entity, image/svg+xml variants, text/html-adjacent types, or vendor XML types that the XML/XHTML parser will script; grep for ‘+xml’ and ’text/xml’/‘application/xml’ comparisons.
  • Cross-platform parity
    Compare the iOS WebCoreURLResponseIOS.mm logic with the macOS/other WebCoreURLResponse implementations (grep for shouldPreferTextPlainMIMEType and adjustMIMETypeIfNecessary across Source/WebCore/platform/network) to ensure the same XHTML entry and overall list are consistent on every platform.
  • Type-string comparison correctness
    Audit MIME comparisons here and nearby for case sensitivity and parameter handling (e.g. ‘application/xhtml+xml; charset=…’ or uppercase), since equality against a bare lowercased literal can be bypassed if the proposed type carries parameters or differing case.
  • Other MIME-to-parser routing decisions
    Look at all sites that decide whether a response is treated as a document vs. inert (grep for mimeTypeInferredFromExtension, isSupportedXMLMIMEType/isXMLMIMEType, MIMETypeRegistry active-type checks) for places where a text/plain or download disposition could still be routed to a scripting parser.

Original Bug Report

The reporter's bug is still restricted on the tracker.