A cross-site scripting (XSS) attack is similar to HTML injection, but includes injecting JavaScript that executes on the client's browser. The client's browser is unable to tell that the script is untrusted and will allow it to execute. Malicious JavaScript can compromise a client by more than just changing the contents of a page; it can be used to steal session cookies, read sensitive information, and inject malware that can execute outside the browser on the user's computer. XSS is one of the most popular and effective web app exploits and is made possible by poor input validation.

There are actually three different categories of XSS:

  • In a stored attack, also called a persistent attack, you inject malicious code or links into a website's forums, databases, or other data. When a user views the stored malicious code or clicks a malicious link on the site, the attack is perpetrated against them. As the name suggests, the injected code remains in the page, as it is stored on the server.
  • In a reflected attack, you craft a form or other request to be sent to a legitimate web server. This request includes your malicious script. You then send a link to the victim with this request, and when the victim clicks this link, the malicious script is sent to the legitimate server and reflected off it. The script then executes on the victim's browser. Unlike a stored attack, the malicious code in a reflected attack does not persist on the server.
  • In a Document Object Model (DOM)-based attack, malicious scripts are not sent to the server at all; rather, they take advantage of a web app's client-side implementation of JavaScript to execute the attack solely on the client.

As with other injection attacks, you should probe input components in the web app for XSS vulnerabilities. The most basic example is finding a form like a search field, comments field, user name/password form, etc., and injecting the following script to open a pop-up on the client's browser:

<script>alert("Got you!")</script>

In most cases, this will reflect off the server and only appear in a single response to the client. So, you'll need to craft a URL to send a victim to:


Crafting a persistent attack will require you to modify the data stored in the web app. You can try to do this with forms that you know store data, like the aforementioned site feedback page. Some injection points might not be so visible, however. Using the product search example, you'd need to actually change the values of the products table itself, rather than just injecting a script into the search results. Depending on the web app's underlying technology, you may be able to change table data by POSTing content in an HTTP request. For example:

POST http://site.example/products Content-Type: application/json {"name": "row", "description": "<script>alert(document.cookie)</script>", "price": 9.99}

Assuming you've obtained authorization (if any is needed), this adds a new row in the products table. The description entry will always trigger an alert on a page that displays this particular row. In this case, the alert will return the user's cookie information.