A Quick Overview of Cross-Site Scripting (XSS)

A Quick Overview of Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) stands as a prevalent and dangerous vulnerability in web applications. It occurs when a malicious actor can inject client-side scripts (typically JavaScript) into web pages viewed by other users. This vulnerability is fundamentally an exception to the browser’s Same-Origin Policy (SOP), which is a crucial security mechanism adopted by every modern browser.


The Same-Origin Policy and the XSS Vector

The Same-Origin Policy dictates that a document or script loaded from one origin (like example.com) cannot interact with resources from another origin (like anothersite.com). This rule is in place to prevent malicious documents from reading or writing sensitive data from other sites.

However, for a modern, functional webpage, exceptions must exist to allow the loading of third-party assets—such as external JavaScript, Cascading Style Sheets (CSS), or images—and this necessity is the vector through which XSS attacks occur.

When a browser processes the src attribute on an HTML tag (like ), it is designed to execute the code that attribute points to. Crucially, the code doesn’t have to be a separate file; it can simply be code included directly in the attribute string. Furthermore, it is not just the src attribute that can execute JavaScript; many other attributes and HTML tags are susceptible.

Demonstrating an XSS Snippet

A classic method for testing for XSS is to use an event handler that triggers a simple JavaScript function, like alert(). This is often referred to as an XSS canary (an initial test payload to confirm a vulnerability exists).

The following is a common example of an XSS testing snippet, utilizing the onmouseover attribute:

snippet text

If this payload successfully executes, hovering over the snippet text will trigger a JavaScript alert() box. The inclusion of document.location within the alert is a simple, effective way of immediately referencing the exact URL where the XSS is taking place, making it easy to document the vulnerability.


Many Varieties of XSS

XSS attacks can be broadly categorized in two distinct frameworks, which help in understanding how the malicious script is delivered and executed.

I. Categorization by Delivery Mechanism

The traditional method of grouping XSS varieties is based on how the malicious payload is delivered to and processed by the browser.

Stored or Persistent XSS

This is considered the most dangerous type of XSS. It occurs when the malicious script is permanently stored on the target server (e.g., in a web application’s database, file system, or other data storage) via a user input, such as a comment, forum post, or profile field.

In the example above, the tag with the malicious JavaScript would be inserted via a form input and then stored in the web app’s database. When any user subsequently views that page, the stored, malicious HTML element is retrieved and rendered by their browser. When that user then performs the necessary action—such as hovering over the element—the onmouseover event triggers the execution of the XSS code.

Reflected XSS

In this scenario, the injected script is reflected off of the target server. This happens when a user’s input, containing the malicious payload, is immediately included and displayed on a response page, such as a search results page, an error message, or another message that incorporates the user’s data.

The payload is not permanently stored. Instead, an attacker typically tricks a user into clicking a specially crafted link (e.g., in an email or message) containing the XSS payload in the URL’s query parameters. The server receives the request, includes the payload in the response (reflecting it), and the victim’s browser then executes the script. Reflected XSS can be very damaging because it leverages the trust of the server the code is being reflected from, making the script appear legitimate.

DOM-based XSS

This is a more specialized and modern type of attack. DOM-based XSS (Document Object Model-based XSS) occurs entirely on the client side. It relies on a client-side script in the legitimate page handling user-supplied data (often from a URL fragment or query string) in an unsafe manner.

The attack relies on a user being supplied an attacker-generated link containing an XSS payload. When the user’s browser opens the link, the legitimate page’s code constructs the DOM (the structural representation of the page) and executes the code based on the attacker’s input, effectively echoing back the payload and executing the malicious script. The key distinction is that the server often does not even see the payload.


II. Categorization by Execution Location

Another way of grouping XSS is by dividing the bug into client XSS and server XSS.

  • Server XSS: This occurs when unverified user data is supplied by the server. This includes both reflected XSS (data supplied through a request) and stored XSS (data supplied from stored locations). The server is responsible for including the malicious data in the page content sent to the client.
  • Client XSS: This refers to the execution of unverified code in the client (the browser), from the same locations (stored or reflected). This category often encompasses DOM-based XSS, as the vulnerability resides in the client-side code’s insecure handling of data.

Understanding these categorizations is essential, as the detection and mitigation techniques can be specific to each variety.


Testing for XSS – Where to Find It, How to Verify It

Discovering XSS vulnerabilities requires systematic testing. The process often involves leveraging specialized security tools to automate or semi-automate the injection of test payloads.

Burp Suite and XSS Validator

One problem with automated and semi-automated solutions for XSS is distinguishing signal from noise—determining which injected payloads actually resulted in successful script execution, and which were simply filtered or rendered inert.

A useful Burp Suite Professional plugin, XSS Validator, helps address this. It runs a PhantomJS-powered web server to receive the results of Burp queries. The extension works by injecting snippets containing an alert() call with a unique, injected string (a canary). The PhantomJS server then monitors network traffic and looks for this unique string, providing a clean way of culling the results of XSS submissions down to absolute confirmed vulnerabilities.

Installation and Setup

  1. Installing the Burp Extension: The easiest way to download the XSS Validator Burp extension is through the Bapp store (Burp App Store). This is accessible by navigating to the Extension tab within Burp Suite and selecting the extension from the marketplace. (It is free.) It is also possible to install the extension manually by following the instructions in the XSS Validator GitHub documentation.
  2. Running the Server: During the actual testing, one must run the server that parses incoming Burp requests. If one clones the XSS Validator git repo (repository), navigation to the xss-validator directory allows the starting of the xss.js script. The server can then be bootstrapped and set to run as a detached background process using a simple command line: phantomjs xss.js & This command executes the PhantomJS (a headless WebKit scriptable with JavaScript) utility, running the xss.js script in the background.

Executing the XSS Attack with Burp Intruder

With the XSS Validator server and Burp Suite running, the next step is to test a specific form input for XSS susceptibility. This process can be demonstrated on a proven testing ground, like the Web Scanner Test Site (webscantest.com), which has been designed to be susceptible to XSS.

  1. Initial Submission: Arrive on the target page with the Burp Proxy Intercept feature initially turned off to navigate without manual forwarding of traffic. Enter something easily recognizable into the form fields being tested.
  2. Intercepting the Request: Navigate back to the Burp Suite GUI and turn the Intercept feature on before submitting the form. Upon submission, the browser favicon may indicate a submission without any visible change on the form. Returning to Burp, the form’s POST request will have been intercepted (note: be prepared to forward other intercepted requests if multiple tabs are open).
  3. Sending to Intruder: Right-click on the intercepted request and select Send to Intruder. This feature allows for the automated manipulation and submission of the request data.
  4. Configuring Payloads: Within the Intruder window, navigate to the Positions tab. The POST request parameters and cookie IDs will likely already be selected as Payload Positions. These defaults can be maintained. The critical changes are made in the Payloads tab to integrate with the XSS Validator extension:
    • Payload Sets: For the second drop-down, Payload Type, select the Extension-generated option.
    • Payload Options: Click Select generator…. This will open a modal where XSS Validator Payloads must be chosen as the selected generator.
    • Payload Processing: Add a new rule here. Choose Invoke Burp extension as the rule type, and then select XSS Validator as the processor.
  5. Setting the Grep Phrase: Head over to the xssValidator tab. A random string is generated in the Grep Phrase field. This phrase acts as the success indicator. The key is to add this grep phrase into the Grep – Match section, located in the Options tab of the Intruder configuration. This ensures that when the attack results are viewed, a checkbox will indicate whether the phrase turned up in an attack response, signifying a confirmed vulnerability.
  6. Starting the Attack: Once all configurations are complete, click the start attack button. An attack window will pop up and begin to self-populate with the results of the multiple XSS snippet submissions. A successful test is evidenced by the presence of the grep phrase for several of the tag/attribute combinations generated by the XSS Validator, meaning the submissions were successful.

XSS – An End-To-End Example (Google Gruyere)

To provide an example of a vulnerability in a real-world scenario, the process can be demonstrated on a deliberately-vulnerable teaching site.

XSS in Google Gruyere

The following example takes place on Google Gruyere, an XSS laboratory operated by Google that explains different aspects of XSS alongside appropriately vulnerable form input. Google Gruyere is based loosely on a social network where users can share public snippets.

Beyond the explicit advertising of the service as being susceptible to XSS, there are often small pieces of text, similar to what is found in real applications, hinting at areas of vulnerability. Limited support for HTML in a specific form is always a potential risk, as it suggests the filters put in place to allow formatting markup (such as

, , and
) may fail to sanitize (clean or filter out dangerous code) a specially-crafted snippet, such as a script tag.

Probing and Testing

  1. Initial Attempt (Slow Pitch): After setting up an account and navigating to the submission form to create a New Snippet, an attempt is made to probe the sanitizing process using a simple, un-obfuscated script that even the most naive filter should capture:
  2. Result of Initial Attempt: When the result of this submission is viewed, no alert() window is displayed, and there is nothing to trigger the execution of the code. The filter has functioned at the most basic level by stripping out the
Previous Post
Relative Path Overwrite (RPO) Exploiting Path Confusion for Defacement

Relative Path Overwrite (RPO): Exploiting Path Confusion for Defacement

Next Post
Detecting and Preventing Injection Attacks: A Deep Dive into SQL, NoSQL, and Scanners

Detecting and Preventing Injection Attacks: A Deep Dive into SQL, NoSQL, and Scanners

Related Posts