What I'm doing:

I'm using OWASP Zap to find vulnerabilities in a site (I have the owner's consent) and Zap came up with a Reflected XSS Vulnerability after I did an active scan on a POST request. It told me that the variable "cn" (the username) was vulnerable to reflected XSS and that the payload "><script>alert(1);</script> would work.

My process:

I went ahead and tried to enter this into the input field called "cn". The input field had a maxlength of 12, I went ahead and did a quick inspect element it and changed that. Then I entered the payload, put in a random value for the password input field and clicked submit.

The Result:

Unfortunately an alert box did not pop up, just a wrong username and password message. I did notice that a little "> that appeared after inserting the payload. When I looked into this I found that the script tag had caused the "> to be parsed as regular characters. <input type="text" name="cn" size="20" maxlength="20" value="<script>alert(1);</script>"> is the html. The "> should not have modified the js though.

The Conclusion

UPDATE: So after thinking about this in the shower I realized the whole point of reflected XSS... that the value provides to the user had to actually be reflected back. The un parameter was never actually being reflected back to me. But this still doesn't answer the question... why did ZAP pick this up as a XSS vulnerability when there clearly is not any XSS?

1 Answer 1


These automated checks work by putting a script tag containing a random token into every field. For example, /someRequest?foo=x&bar=y might become:

GET /someRequest?foo=<script>alert("147230578")</script>&bar=<script>alert("561972456")</script>

It maintains a map of fields and the random values it chose (in this case foo=147230578, bar=561972456) in order to trace which parameter is injectable.

It then checks to see if <script>alert("147230578")</script> or <script>alert("561972456")</script> appear in the page without encoding. If the string is found, it knows XSS is very likely possible. If not, it either didn't appear in the page at all or it got HTML encoded.

In your case, it found that if it did get those strings reflected back, and identified which field was injectable. The reason it didn't execute is that the script tag got injected into a HTML attribute.

So, looking at your injection:

<input type="text" name="cn" size="20" maxlength="20" value="<script>alert(1);</script>">

What happens here is the HTML is malformed, so the browser's renderer just tries to make the best of it, ignores both tags, and closes everything after the </script>. It then sees "> which it assumes is content and renders it on the page.

If we instead inject "><script>alert(1)</script> into the parameter, we get this:

<input type="text" name="cn" size="20" maxlength="20" value=""><script>alert(1)</script>">

This time the input tag is closed, which causes the script tag to get executed. Successful XSS! Again, the "> at the end just gets treated as content.

For a bonus round, what might we do if the vulnerable parameter doesn't allow the use of triangle brackets? Since we're already in an attribute, we can manipulate the input element we're injecting into in order to execute script:

" onmouseenter="alert(1)" x="

This creates the following output:

<input type="text" name="cn" size="20" maxlength="20" value="" onmouseenter="alert(1)" x="">

Note that the x attribute doesn't do anything, it's just there to let us maintain valid HTML; unknown attributes are just ignored.

In this case, when the user's mouse enters the input element, it executes the JavaScript and we get XSS again.

But requiring user interaction sucks! We could use onload but this is often finnicky. Instead we can utilise some CSS tricks to force the user interaction:

" onmouseenter="alert(1)" style="display:block;position:absolute;top:0;left:0;width:50000px;height:50000px;z-index:999999;

This then becomes:

<input type="text" name="cn" size="20" maxlength="20" value="" onmouseenter="alert(1)" style="display:block;position:absolute;top:0;left:0;width:50000px;height:50000px;z-index:999999;">

The style here looks like a mouthful but it's quite simple:

  • Make the element display as a block element (so we can size it arbitrarily)
  • Make the element's position absolute within the window (so we can set its position to anywhere)
  • Move the element to (0,0)
  • Make the element completely fill the page (so the user's mouse has to enter it!)
  • Make the element appear on top of everything else.

Hopefully this explains how this all works and how you can go from the example given by ZAP to a working XSS exploit.

You must log in to answer this question.

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