XSS Attacks

XSS flaws occur whenever an application takes untrusted data and sends it to a Web browser without proper validation and escaping. Typically, this attack aims to steal login credentials or other personal information. For example, the threat actor might be able to exploit a Web application’s unsensitized user input or HTTP requests.

These vulnerabilities allow attackers to execute a script, like malicious JavaScript, in the victim’s browser. This code can hijack a user’s session cookies, which might contain usernames, passwords, or other personal details. With that information, attackers might gain control of a user’s email, social media or even bank account. XSS can also be used to deface websites or redirect the user to malicious sites.

A threat actor might use any of three types of XSS attacks to exploit a website.

1. Non-persistent or reflected attack

2. Persistent (or stored) attack

3. DOM (Document Object Model) attack

1. Non-persistent or reflected attack

A non-persistent attack requires direct interaction by the user visiting the site. An attacker might send a malicious version of the URL or exploit a form on the vulnerable website. This type of attack might be sent to a victim with the intention of stealing their session cookies and ultimately their account.

Often a threat actor will send this as an email similar to a phishing attack. The example below contrasts a site-generated URL versus a malicious URL encoded and sent by a threat actor. In the malicious URL, the attacker relies on the browser to execute the JavaScript added to the link. This example uses the location object to send the user’s session cookie to the attacker’s site. From here, the threat actor has a Common Gateway Interface (CGI) script that will store or display the information sent.

Intended URL:


Malicious URL:

http://domain.tld/?sess=12312312&user=<script>// <![CDATA[
// ]]></script>

Information that could be sent to the attacker:

Persistent (or stored) attack

The bad guys often deploy persistent cross site by deploying or exploiting an application or plugin that stores user input in a database. This attack often stores the malicious injection in the website’s database and triggers automatically whenever someone visits that page. This attack doesn’t require the user to click on any malicious links and can be much harder to detect while Web browsing.

Want an example? Think back to July 2013 and the WordPress® and Bit51 Better WP Security plugin. For this attack, the threat actor would visit the website while using an intercepting proxy such as Burp Proxy. The attacker would start by visiting a page that does not exist for the site. Next, he modifies the GET request to include a malicious JavaScript injection as part of the path. The security plugin logs information about any time someone visits a page and receives a 404-status code. Therefore, the modified GET request is stored in these logs, which are kept in the website’s database. When the website’s admin clicks the “Logs” tab for the plugin, this form action queries the database’s wp_bwps_log table. When the CMS pulls from the database, this variable is hydrated and the stored XSS is executed.

This exploit might be used to hijack the user’s session, which would allow the attacker to modify the site. Below are screenshots of this vulnerability successfully exploited.

Note: WordPress and the Bit51 Better WP Security Plugin have since been updated to guard against this issue.

Threat actor requests page:

Injection using proxy:

Alert when admin clicks on Logs tab:

Stored XSS in the Database:

3. DOM (Document Object Model) attack

The threat actor achieves a DOM-based XSS attack by modifying the DOM environment in the user’s browser. This is the result of exploiting the original client-side JavaScript hardcoded into the site. While uncommon, this attack is particularly difficult to address because the HTTP response of a page is not changed, and no unique data is sent to the server.

A DOM attack is unique and hard to detect because it occurs client-side, whereas stored and reflected XSS exploit a server-side flaw.

A threat actor could use a JavaScript parameter, such as the site language, which is handled client-side in the DOM. The example below shows an XSS attack that exploits JavaScript intended to set the language of a Web page. By proceeding the malicious JavaScript with a “#” symbol, the script is run locally and never sent to the server. The malicious code is stored in the DOM’s owner Document object and executes as the page loads.

Client-side JavaScript:

document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>");
document .wirte(“File not found”);
once the data is not found in the sense how to make it in one section to another

Malicious URL sent by attacker:


View of the DOM using Firebug:

XSS prevention best practices

Methods can be both applied on the client- and server-side to prevent script injection attacks. However, you should consider that in general, there’s no best practice on the client-side that can prevent script injection attacks, simply because all such safeguards can be circumvented by the attacker when sending requests to the server, and therefore client-side methods can only be relied on as ways to make XSS exploits harder for the attacker.

Here are practices that can help mitigate and eliminate the threat of cross-site scripting attacks.


Client-side validation cannot be relied upon as a security means to prevent XSS attacks but rather as a means to guide the user into entering correct input. Server-side validation, however, is a must-have when it comes to combating cross-site scripting. You should verify every single input being submitted by the user against a set of rules to make sure it is within the defined range. Validation includes using simple checks, regular expressions and encoding/escaping functions to check the format of the input and to replace characters and strings that might have malicious purposes. For instance, if the user has entered the word “” in the input, it should be escaped properly to display it as a text instead of rendering it as an HTML tag. Escaping is especially useful if your site doesn’t need rich content.

Controlling page charsets

Defining the character set of your pages with meta tags can greatly reduce the number of possible forms script injection can be implemented. This is especially important since some browsers don’t specify default charsets for pages, and some servers don’t allow charset headers to be sent along with responses.

So, for instance, if your site isn’t meant to display characters outside the ISO-8859-1-character set (which encompasses English and most European languages) you can use the following tag in your pages’

in order to prevent charset-based XSS attacks:

<META http-equiv="Content-Type" content="text/html; charset= ISO-8859-1">

Best practises to prevent any type of XSS attack (persistent, reflected, DOM, whatever).

1 . Strictly validate all input. For example, if you're asking for a UK postcode ensure that only letters, numbers and the space character is allowed. Do this server-side and if validation fails, display a message to the user so that they can correct their input. Do this for all variables outside of your control, including query string, POST data, headers and cookies.

2 . Add yourself some security headers. Namely

  • X-XSS-Protection: 1; mode=block to activate reflective XSS browser protection into blocking mode instead of filtering mode. Blocking mode stops attacks like this.

  • X-Content-Type-Options: nosniff to prevent JavaScript being inserted into images and other content types.

  • Content-Security-Policy: with strict script-src and style-src's at least. Do not allow unsafe-inline or unsafe-eval. This is the daddy of headers for killing off XSS.

3 . Follow the rules in the OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet when outputting values, however for rule #3 I'd do the following instead:

  • Use HTML data attributes to output anything dynamic on the page.

  • e.g. <body data-foo="@foo" />

  • Where @foo will output an HTML encoded version of the variable. e.g. " /> would give <body data-foo="&quot; &#x2F;&gt;" />

  • Grab these values out using JQuery or JavaScript: var foo = $("body").data("foo");

  • This way you don't need to worry about any double encoding, unless your JavaScript later inserts as HTML, however things are still simpler as you deal with the encoding there too instead of mixing it all together.

  • Use a function like below to HTML encode if you're using document.write, otherwise you could introduce a vulnerability. Ideally though use textContent or JQuery's text() and attr() functions.csscs

  • Tackle these in reverse order. Concentrate on #3 as this is the primary mitigation for XSS, tells the browser not to execute anything that slips through and #1 is a good defence-in-depth measure (if special characters can't get in, they can't get out). However, #1 is weaker because not all fields can be strictly validated and it can impair functionality (imagine Stack Exchange without the ability to allow "

results matching ""

    No results matching ""