v152 · removal · xml
<?xml-stylesheet type="text/xsl" ?>
An XSLT processing instruction in an XML document — <?xml-stylesheet type="text/xsl" href="style.xsl"?> — makes the browser transform the document with the referenced stylesheet before rendering, typically turning raw XML into HTML. This behavior is deprecated since Chrome 143 and removed from Stable in Chrome 158: the document then renders as raw, untransformed XML (with a warning banner pointing users at an extension). The same PI with type="text/css" is not affected.
After Chrome 158, any user-facing flow that relies on an XSLT-transformed XML response renders the untransformed XML instead. Add the one-line polyfill to the XML itself, move the transform server-side, or register the deprecation origin trial for time.
syntax
The PI grammar is defined by Associating Style Sheets with XML documents; the transformation semantics are XSLT 1.0 (W3C Recommendation, 1999). The removal targets the XSLT type values only:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="demo.xsl"?> <!-- removed -->
<?xml-stylesheet type="application/xslt+xml" href="demo.xsl"?> <!-- removed -->
<?xml-stylesheet type="text/css" href="styles.css"?> <!-- NOT removed -->
<page>
<message>Hello World.</message>
</page>
| Pseudo-attribute | Role |
|---|---|
type="text/xsl" / type="application/xslt+xml" | Selects XSLT processing — the removed behavior |
type="text/css" | Selects CSS styling of the raw XML — remains supported |
href | Stylesheet URL; loaded by the browser's native loader (synchronously, historically not CORS-bound) |
what happens when disabled
- Chrome receives the XML document and finds the XSLT processing instruction.
- With the
XSLTfeature disabled, the PI is ignored: no transformation runs. - Chrome renders the raw XML document (its standard XML view) and shows a warning banner that links directly to an extension search page, so affected users can discover the XSLT polyfill extension.
- A deprecation warning is logged to the console (from 143) and a deprecation report with id
"XSLT"is emitted (see detection).
migration: one line of polyfill
The polyfill can be added to the XML document itself — a single <script> element (with the XHTML namespace declaration, required so the script executes in an XML document):
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="demo.xsl"?>
<ROOT>
<script src="xslt-polyfill.min.js" xmlns="http://www.w3.org/1999/xhtml"></script>
...content...
</ROOT>
Mechanism: the script detects the XML document type and the XSLT PI, re-fetches the source document (to get the clean original byte stream), fetches the stylesheet, runs the WASM libxslt engine, and replaces the document's content with the transformed result. Scripts in the transformed output are re-created so they execute, and synthetic DOMContentLoaded/load events fire. For RSS/Atom feeds the added script is safe for feed readers because it sits as a direct child of the root element.
Documented limits for the PI path:
- CORS — stylesheet and
xsl:include/xsl:import/document()resources load throughfetch(); cross-origin stylesheets that native XSLT accepted can now be blocked. Host the stylesheet same-origin or serve CORS headers. - Quirks — the replaced content lives in an XHTML document, which always renders in no-quirks mode; transformed HTML that relied on quirks rendering (no
<!DOCTYPE>) can look different. - Encoding — the single-file WASM build requires UTF-8.
- Loading latency — the WASM engine compiles on first use; the polyfill offers a
window.xsltPolyfillSpinnerhook for a loading indicator.
affected use cases and recommended paths
| Use case | Recommended path |
|---|---|
| RSS/Atom feeds styled for accidental human clicks | Prefer <link rel="alternate" type="application/rss+xml"> discovery on HTML pages; otherwise add the one-line polyfill to the feed |
| Embedded devices serving XML+PI on local networks | Update firmware (server-side transform, JSON, or polyfill) where possible; where the device cannot change, use the browser extension |
| Sites using XSLT as a lazy templating layer | Polyfill as stopgap; server-side transformation; long-term migration to a JS/JSON framework |
XML+CSS documents (type="text/css") | No action — not part of the removal |
browser compatibility
| Browser | PI processing today | Removal plan |
|---|---|---|
| Chrome | Supported (Baseline widely as part of xslt) | Deprecated 143; Stable removal 158; trial/policy until 176 |
| Edge | Supported | Follows Chromium |
| Firefox | Supported | Removal planned (Gecko supportive); no dated plan on the record |
| Safari | Supported | Removal planned (WebKit cautiously supportive) |
No dedicated BCD entry exists for the processing instruction itself (the xslt web-feature covers the capability; webstatus.dev); treat this table as interim data compiled from the linked primary sources.
security and privacy
- The PI path is the riskiest half of the feature: it processes an attacker-supplied stylesheet through libxslt during page load, with no script required — the exploit class documented at OffensiveCon 2025.
- Native PI stylesheet loads were historically not CORS-bound; the polyfill's
fetch()-based loads are CORS-checked, which is stricter (and the cause of most polyfill failures, per the ChromeStatus interop notes). - The browser extension route grants a user-installed extension access to raw XML pages; weigh that against firmware updates for managed devices.