XSSing TypeErrors in Safari
Published: Fri, 30 May 2025 17:36:47 GMT
Updated: Fri, 30 May 2025 17:39:49 GMT
On my lunch break, I had a spare half hour. I tend to get a lot done during lunch - writing blog posts, building web apps… I even wrote a book 30 mins each day for a few months. Anyway, I digress.
I was playing around with HackPad on Hackvertor when I remembered that Safari used to have an XSS issue in the actual TypeError
. I’d used it before, but it caught my attention again because I’d recently been researching ways to conceal payloads in window.name
and execute them using exception handling.
In case you’re not familiar, here’s what the traditional vector looks like:
throw onerror=eval,name
Pretty cool - but it got me thinking: what if I could combine the TypeError XSS with the error handler somehow? That way, I could drop the need for the throw statement altogether and still trigger the exception handler.
The TypeError
XSS works like this:
new 'foo"bar'//TypeError: "foo"bar" is not a constructor
TypeErrors
don't prevent the JavaScript from executing like syntax errors do so we can use this. If you take a look at the exception message you'll notice there are three double quotes in and around the foo bar
string. Safari it seems converts the single quotes to double quotes but does not escape the middle one which produces XSS in the actual TypeError
.
Let's stick a XSS payload in there:
new 'foo"-alert(1)//' //TypeError: "foo"-alert(1)//" is not a constructor
If you look at the exception message and imagine you are treating this as JavaScript, TypeError:
gets treated as a label statement, the double quote closes the string, the alert
function is called and then the single line comment removes the rest of the exception message, there is more but I trimmed it to be easier to read.
How can we execute it?
//Note this won't work in the console onerror=eval; new 'foo"-alert(1)//'
So the onerror
handler is assigned to eval which basically means any exceptions get sent to this function. Then I use the new
operator on the string which creates a TypeError
and XSS's it. The TypeError
string is then passed to eval which executes the code.
We can now get arbitrary JS when using new
with strings and of course window.name
is also a string so we can place this payload into a window.name
and call new
on it. But Safari makes the window.name
blank when navigating! However, we can get round this using the target
attribute and probably window.open
too. Anyway the final step is to stick the payload in there and then point it to the XSS vector and bingo we have have it!
onerror=eval,new name