Common Web Application Vulnerabilities – Cross-Site Scripting

As we continue our series explaining some of the most common web application vulnerabilities we encounter during penetration tests, we arrive at cross-site scripting (XSS). XSS comes in at number 7 on the most recent OWASP Top 10 release, so it is still an issue for a significant number of applications and organizations. Caused by a lack of input validation and untrusted content being rendered in an application page in an executable format, this type of vulnerability can be exploited by an attacker to run arbitrary JavaScript in a client’s browsing session. This arbitrary code execution can allow an attacker to gain control of that user’s host through browser-based exploitation, steal their session cookie in order to gain unauthorized access to the target web application, or even launch a keylogger on a particular page of an application. The possibilities are endless and limited only by the capabilities of the JavaScript language, as code can be included from an attacker-controlled server.

XSS falls into three high-level categories: reflected, persistent/stored, and DOM-based. These different categories are due to different delivery methods and impacts, even though the injected script and exploitation results are the same. Let’s break down the key differences:

Reflected Cross-Site Scripting (XSS)

Description: This flavor of cross-site scripting occurs when a vulnerable parameter in a GET/POST request can have JavaScript placed into it, the tampered request can be sent to a victim through out-of-band methods, and when the user visits the affected page or link, the code is automatically executed.

Delivery Method: Requires some type of social engineering to transmit an affected link/URL to client or coerce a client into visiting an infected web page.

Impact: Code is executed in client’s browsing context. For session hijacking or other application-specific exploits, the victim must already be authenticated to the target application such that they have a session cookie issued.

Example: I send you the link<script>alert(document.cookie)</script> via email and when you click on it, your session cookie is displayed in an alert box in your browser. In reality, an attacker would not display this content but send it via an HTTP request to one of their web servers.

Persistent/Stored Cross-Site Scripting (XSS)

Description: With persistent/stored cross-site scripting, malicious script can be stored within the application somehow (usually in the back-end database) such that when another user browses to a page that displays that variable, the code is executed in that user’s browser. This is sometimes referred to as a watering hole attack, as any user that visits that particular “hole” is compromised without any interaction.

Delivery Method: Different from reflected XSS, the malicious code in this case is stored within and delivered from within the vulnerable application. No victim interaction required and multiple victims can be compromised from a single exploited location within an application.

Impact: Usually higher impact than reflected for multiple reasons:

  • Social engineering and out-of-band delivery is not required for exploitation
  • Victim interaction is not required
  • Multiple victims can be compromised by a single attack
  • Victims will usually already be authenticated to the application when they are exploited

Example: The most often seen example of this is when a user can type <script>alert(“You’ve been pwned!”)</script> into a comment box, post the comment, and their message pops up for every subsequent user who visits that comment page.

DOM-based Cross-Site Scripting (XSS)

This somewhat newer variant of XSS (it was first documented in 2005) is sometimes referred to as client-side XSS. This variant occurs when untrusted user input is incorporated into the document object model (DOM) of a page, rather than being included in the page response from the server. At the end of the day, it is still very close to reflected XSS in that the malicious payload needs to be delivered to a victim and the root cause is due to input that isn’t properly validated and then directly incorporated into client-side script. OWASP has a very basic example of this you can check out here.


On the bright side, it is becoming easier and easier to secure new applications from cross-site scripting vulnerabilities. Many new language frameworks build in protections that automatically encode all untrusted output, like Python Flask for example. ASP.NET has request validation controls that help filter malicious content before it is processed by the application server. Additionally, there are built in functions in most languages that help support proper output encoding such that text isn’t rendered in an executable format.

But in addition to output encoding, strong input validation is also important. For XSS just like all other flavors of injection attack, any way that you can limit the malicious content that is processed by the server will improve its security posture. Client-side and server-side input validation has to be used that allows a whitelisted set of values (where possible), validates the data type submitted (e.g. no strings in an integer field), checks the acceptable content length (maximums on fields in the user interface that match variable lengths set on the back-end), and filters out unwanted characters (where possible).

Finally, if you’re looking for some additional protection against these kinds of attacks, you can always consider a Web Application Firewall (WAF) to provide some defense in depth. These devices are pretty good and blocking a lot of the low hanging fruit when it comes to malicious content associated with injection. And while they are not a silver bullet and can likely be bypassed given enough time, a WAF will certainly help raise the bar for your website security and make it more difficult for an attacker trying to compromise it.

As always, if you want to explore having a web application penetration test conducted to see if you are vulnerable to any XSS flaws or if you just have questions about this type of vulnerability in general, feel free to reach out!