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

    MentalJS bypasses

    By Gareth Heyes (@hackvertor)

    Published 11 years 10 months ago • Last updated March 24, 2025 • ⏱️ < 1 min read

    ← Back to articles

    I managed to find time to fix a couple of MentalJS bypasses by LeverOne and Soroush Dalili (@irsdl). LeverOne's vector was outstanding since it bypassed the parsing itself which is no easy task. The vector was as follows:

    for(var i i/'/+alert(location);0)break//')

    Basically my parser was inserting a semi colon in the wrong place causing a different state than the actual state executed. My fix inserts the semi colon in the correct place. Before the fix the rewritten code looked like this:

    for (var i$i$; / '/+alert(location);0)break//')

    As you can see the variables have been incorrectly joined and so the next state is a regex whereas Mental thinks it's a divide. After the fix the rewritten code looks like this:

    for (var i$;i$ / '/+alert(location);0)break//')

    So now the divide is an actual divide. Technically I shouldn't be inserting a semi-colon in the for statement, I might fix this at a later stage if I have time.

    The second bypass was from Soroush that basically assigned innerHTML on script nodes bypassing the rewriting completely. Cool bug. The fix was pretty simple, I prevented innerHTML assignments on script nodes. Here is the bypass:-

    parent=document.getElementsByTagName('body')[0]; img=document.getElementsByTagName('img')[0]; x=document.createElement('script'); x.innerHTML='alert(location)'; parent.appendChild(x);

    ← Back to articles