I have the following script:

function filter() {
    const inputstring = JSON.stringify(document.getElementById('input').value)
        .replace(/[<]/g, '%lt')
        .replace(/[>]/g, '%gt');
    const userTemplate = '<script>let a = %userData%</script>';
    document.write(userTemplate.replace(/%userData%/, inputstring));

First of all, it reads the string submitted with the help of HTML input. Then, it analyzes the string for the < and > symbols. If they are found, they get replaced. Then, it replaces %userData% with our input and writes it.

How can I bypass this filter and exploit XSS here? The line <script>let a = %userData%</script> looks quite interesting as it already contains a script tag and a variable a. It is also quite pointless to use > and < symbols in input, so I guess we are forced to use the variable a. The problem is that all my input gets surrounded by double quotes (the result is <script>let some = "text"</script> when my input is text), so I can not execute any functions. Maybe it is somehow possible to get rid of the quotation marks?

  • I'm slightly uncertain as to the context here. So you have an element with id="input" and you're placing a filter on that content and then placing that content into a script tag on the page. Does this just happen when the page is first loaded or just whenever the input changes? Is it possible that the input you're loading was entered by a different user?
    – Tophandour
    Commented Nov 12, 2018 at 21:16
  • I don't think the let a = ... line is directly exploitable. But what happends with a after that? Is it inserted into the DOM somehow? There you may still have opportunities for exploitation. Not sure, though.
    – Anders
    Commented Nov 13, 2018 at 10:11
  • If we have string concatenation, can't we do a 1; alert(123); ?
    – ndrix
    Commented Nov 27, 2018 at 2:06

3 Answers 3


Based on your code snippet, it seems like the protection is just using client side JavaScript to protect from XSS. All you would have to do is open up the console on that page and redefine the filter method. I really hope that the XSS protection isn't done client side or that this is a CTF.

  • 3
    How would that help you exploit an actual victim? You can't rely on the victim using the console for you (or if you can, you won't need XSS). Client side XSS protection is not necesaraly bad.
    – Anders
    Commented Nov 13, 2018 at 10:07
  • XSS attacks work injecting JS into web pages that is run when another user goes to that page. For example a form like this will display my text once I submit it. If I added JS to the form and you visited the page, I could make you run some JS. However, most web pages will keep you from using the "<" in posts (if you look at the code it will really be an escaped version). If stack overflow did this client side like how your script suggests, I could just remove the check, then post some JS and pwn you :)
    – MikeSchem
    Commented Nov 14, 2018 at 1:16
  • 1
    How would you pwn me by removing the check on your computer? Or if you mean you would remove the check on my computer, how would you do that? You can't fire up the console on my computer, and the check prevents you from running scripts.
    – Anders
    Commented Nov 14, 2018 at 8:58
  • 1
    I think OP is implying that the check only applies to when the form is uploaded, not when the resulting data is downloaded onto another user's computer.
    – kemp
    Commented Nov 26, 2018 at 20:19
  • Thanks @rockhopper72 that's defiantly the disconnect.
    – MikeSchem
    Commented Nov 27, 2018 at 19:57

Yes, this filter can be bypassed by playing around with special replacement patterns.


The output of the payload above will look like something along these lines:

</script><script>let a = "</script><script>let a = alert(1)//"</script>

If you are interested in learning more about similar bypass techniques, I highly recommend giving http://prompt.ml/ a go.


I can't find any direct way to exploit this filter. However, you should never feel confident with a homebrew XSS filter like that. And there might be indirect ways.

The value property of a HTML element will always be a string. So JSON.stringify will escape and enclose in double quotes. I can think of three ways out of the JS string context, but none of them work:

  • With a script tag or HTML comment: The replacement of < and > stops us here.
  • With a double quote: These gets escaped during JSON encoding.
  • With a newline: Also gets escaped during JSON encoding.

So I would go looking for indirect ways to exploit this. What happends to the variable a? Does it get inserted into the DOM somewhere? For instance, if you find code like this you'll be able to exploit it:

element.innerHTML = `<img src='${a}'>`;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .