The Spanner logo
    • Home
    • Blog
      • Blog home
      • RSS
    • Login
    • Home
    • Blog
      • Blog home
      • RSS
    • Login
    The Spanner logo

    The Spanner
    Web security blog

    Made by Gareth Heyes
    Follow me on Twitter: @garethheyes

    Javascript for hackers!

    Hackvertor logo
    Shazzer logo
    My Github account
    Recent posts
    Introducing Feedworm: A Privacy-First RSS Reader That Lives in DevToolsSpeedy RSVP extensionAutoVaderHackvertor history and tag finderShadow Repeater v1.2.3 releaseBurp Hackvertor v2.1.24 releaseHacking roomsXSSing TypeErrors in SafarivalueOf: Another way to get thisMaking the Unexploitable Exploitable with X-Mixed-Replace on FirefoxThe curious case of the evt parameterCSS-Only Tic Tac Toe ChallengeRewriting relative urls with the base tag in SafariBypassing DOMPurify with mXSSNew IE mutation vectorHow I smashed MentalJSMentalJS DOM bypassAnother XSS auditor bypassXSS Auditor bypassBypassing the IE XSS filterUnbreakable filterMentalJS bypassesmXSSJava SerializationBypassing the XSS filter using function reassignmentRPOSandboxed jQueryX-Domain scroll detection on IE using focusEpic fail IEnew operatorDecoding complex non-alphanumeric JavaScriptHacking FirefoxDOM ClobberingBypassing XSS AuditorThe evolution of codeNon-Alpha PHP in 6-7 charsetTweetable PHP-Non AlphaMentalJS for PHPOpera x domain with video tutorialSandboxing and parsing jQuery in 100ms

    mXSS

    By Gareth Heyes (@hackvertor)

    Published 12 years ago • Last updated March 26, 2025 • ⏱️ 3 min read

    ← Back to articles

    Mutation XSS was coined by me and Mario Heiderich to describe an XSS vector that is mutated from a safe state into an unsafe unfiltered state. The most common form of mXSS is from incorrect reads of innerHTML. A good example of mXSS was discovered by Mario where the listing element mutated its contents to execute XSS.

    <listing>&lt;img src=1 onerror=alert(1)&gt;</listing>

    When the listing’s innerHTML is read it is transformed into an image element even though the initial HTML is escaped. The following code example shows how the entities are decoded.

    <listing id=x><img src=1 onerror=alert(1)></listing> <script>alert(document.getElementById('x').innerHTML)</script>

    The expected result of the alert would be “&lt;img src=1 onerror=alert(1)&gt;” however IE10 decodes the entities and returns "<img src=1 onerror=alert(1)>" instead. The vector mutated from a safe state to an unexpected unsafe state. mXSS can work on multiple reads of the data, the first render is the actual HTML and every read of innerHTML is counted as another mutation since it could be decoded multiple times. To help testing for mutation vectors I’ve created a simple tool that mutates the HTTML multiple levels. It does this by reading and writing the HTML. The tool is available here:

    mXSS tool

    If you try the above vector using this tool you can see how the vector mutates and executes. Because mutation XSS works on multiple levels the following HTML will be perfectly valid if you change the mutation level to 2. This reads and writes the HTML twice, you can of course increase the mutation value and continue encoding forever.

    <listing>&amp;lt;img src=1 onerror=alert(1)></listing>

    HTML parsers often get confused and understandably because of the complex interaction between HTML, entities and different document types. One of those confusions happens with HTML and XHTML. In IE9 document mode the entities will be decoded by confusing the parser that it’s a XHTML element rather than a HTML element. Visit the mXSS tool in IE9 mode at the following URL

    mXSS tool in IE9 mode

    By using a forward slash which is ignored in HTML but in XHTML it’s treated as a self-closing element we confuse the HTML parser into rendering the entities and breaking out of the style element and executing an image element. This bug was fixed in IE10 but thanks to the useful backwards compatibility modes we can render using IE9 and still execute.

    <style/></style><img src=1 onerror=alert(1)></style>

    More elements work this way in IE9, the following Shazzer URL shows which elements decode entities in this way.

    Incorrect innerHTML serialization

    Another cool IE9 mutation vector is using the “<%” element, this element acts as a comment and it’s possible to mutate attributes inside other elements combining a script based vector. An example is below.

    <script> x="<%"; </script> <div title="%></script>&quot;<img src=1 onerror=alert(1)>"></div>

    ← Back to articles