David Bushell's "Death comes for XSLT" (2026-11-03) drew 60 points and 55 comments on Lobsters and reopened the "don't break the web" argument. With Chrome 158 turning off XSLT on Stable on 2026-11-17, this piece looks at how in-browser XSLT actually worked, why it can't simply be swapped out, and what that means for choosing a migration path.
Browsers expose XSLT through two entry points.
<?xml-stylesheet type="text/xsl" href="feed.xsl"?> at the top of an XML document, and when the browser navigates to that XML it fetches the XSL and renders the result (usually HTML) as the document. This is how RSS/Atom feeds are made human-readable, and how embedded devices serve raw XML as their admin UI.XSLTProcessor API. JavaScript creates new XSLTProcessor() and transforms an in-memory XML DOM with importStylesheet() plus transformToFragment() / transformToDocument().Chrome says about 0.02% of page loads use XSLT, and under 0.001% use the processing instruction. zcorpan redid the analysis on the 2026-09-01 HTTP Archive crawl (whatwg/html#11523): the PI appears on 632 pages and XSLTProcessor on 2,418. In a sample of 200 loaded in Chrome Canary 158 with XSLT on and off, 12 broke and 85 got worse, which extrapolates to about 120 broken pages and 1,260 degraded ones. The broken ones are sites where the XML document is the page (portals, a phone directory, a climate data site) and Flarum forums that haven't moved to the polyfill. Most of the degraded ones are sitemaps and feeds. None of the 13 hits in the top 100k sites break.
The numbers are small, but the breakage is concentrated: devices that can't be updated, old personal sites, and feeds, which are places where nobody maintains the code, or the people who do can't act.
Browsers only ship XSLT 1.0 from 1999. Neither 2.0 (2007) nor 3.0 (2017) was ever implemented. Chromium relies on GNOME's libxslt and libxml2, both written in C. Chrome's guide cites CVE-2025-7425 and CVE-2022-22834 and argues that the less a feature is used, the less review and fuzzing it gets.
Firefox has its own implementation, but it's in the same position. Mozilla Hacks' May 2026 post on AI-assisted auditing highlights "a 20-year-old XSLT bug in which reentrant key() calls cause a hash table rehash that frees its backing store while a raw entry pointer is still in use," and notes it was one of several sec-high XSLT issues. Mozilla's standards-positions#1287 said that if removal proved impossible, browsers should fix XSLT's security fundamentals "even at the cost of performance," and mentioned sandboxing libxslt as an option.
One distinction matters here: only XSLT is going away, not XML. Chrome plans to move XML parsing from libxml2 to a Rust parser, and says the switch should be invisible to web developers. Styling XML with CSS via <?xml-stylesheet type="text/css"?> keeps working.
XSLTProcessor is an ordinary class, so a WebAssembly version can replace it. Mason Freed's xslt_polyfill compiles libxslt and libxml2 to Wasm with Emscripten and implements importStylesheet, transformToDocument, transformToFragment, and parameter handling.
The processing instruction is the hard part. When the browser navigates to XML, it finishes the transform before any script runs. As the polyfill's README explains, in a browser with native XSLT enabled, a <script> in the XML is just input to the transform. The polyfill never runs, and no flag in the XML can change that. So the behavior is mutually exclusive: native transform when native is enabled, polyfill only when it isn't.
Given that, the polyfill asks you to put one XHTML-namespaced <script> directly under the XML root element: