Reading Time: 6 minutes

Introduction to Cross-site scripting (XSS)

by Kamil Pabin, posted 16/12/2020



As of 2020, many might think that Cross-site Scripting (XSS) vulnerabilities are well explored and that the vast majority of them are addressed by frameworks we use. However, numerous examples from this year alone show XSS remains an issue, with possibly the most famous XSS vulnerability of the year being found in Google Sheets. In this article, I will take you through the basics of Cross-site Scripting (XSS), focusing on the most common types of XSS attacks and the various ways applications are exposed.


That’s not my code!

XSS is probably one of the most known web application vulnerabilities. At a high-level, it involves injecting malicious code into a 3rd party web page. That malicious code will later be executed when the page is visited by users. Going a little deeper, XSS vulnerabilities can be divided into three main families, each with its own way of compromising an application. Even though cases in each group share similarities, each is unique in its own way. Let’s walk through each family of vulnerability by showing a simple example, and discussing how you can protect your application against such attacks.


Reflected XSS

A reflected XSS is a specific type of XSS whose malicious script bounces off of another website to the victim’s browser. It is passed in the query, typically, in the URL. It makes exploitation as easy as tricking a user to click on a link.

In 2017 a hacker managed to implement reflected XSS in Google Docs Awarded him a bounty for his trouble!

To simulate how the hacker did this, let’s imagine we have an online shop, and one of the features is search for products by phrase. This search bar might look like one shown in Figure 1.

Online shop search bar

Figure 1. Online shop search bar

When we search for specific phrases, we may not get any results (Figure 2). Notice that the product_name is part of the URL

Searching for product in online shop

Figure 2. Searching for product in online shop

Next, let’s try searching for a phrase with a HTML tag, for example <b>. This time, when we get a response, everything after our search phrase is in bold! This might indicate that the application is vulnerable to XSS attacks.

Injecting b tag

Figure 3. Injecting b tag

Let’s do one last test, this time we inject JavaScript code <script>alert(1)<script/>. This time when we hit enter, alert popup shows. This confirms that this page is vulnerable to the type of XSS attack known as reflected XSS. What we searched for was reflected by the server (see Figure 4).

Successful injection of script tag

Figure 4. Successful injection of script tag

Attackers are not limited to HTTP GET, they can also inject code inside tag event methods or element class names.

So how do you defend against this kind of attack? Simple, you must URL encode all user input. These are what’s known as HTML entities and are replaced as follows:

HTML entityreplacement









Table 1. HTML entities and its replacements

What’s shown here is just the tip of the iceberg. For more detail, I encourage you to read the book written by Securitum (in Polish).


Stored XSS

This vulnerability was discovered in Twitter in 2018 and caused a massive tweet storm. The text input field wasn’t secured against XSS resulting in the possibility of compromising the retweet button.

In this example, let’s take the same page for searching for products, but this time the seller has an option to upload a description of a product, using HTML tags.

Product page

Figure 5. Product page

This allows the seller to use formatting tags so description looks more attractive to site visitors. This description is taken as raw input and stored inside a database, so every time a client visits the product page, it will be rendered.

Product description updated with b tag

Figure 6. Product description updated with b tag

But what happens when we inject a script from the previous example as part of the description? When a client visits such a site, the JavaScript code is executed and a popup is displayed. Furthermore, this code is executed in the context of the currently logged-in user!

Injected javascript is executed

Figure 7. Injected JavaScript is executed


After javascript execution rest of the page is rendered

Figure 8. After JavaScript execution rest of the page is rendered

This could lead to stealing authentication tokens, or in this case an attacker could inject code which automatically buys a product the same second you visit the page. This example is highly exaggerated, but this is just basics, in real-life applications, there could be input fields for names, or help questions for password recovery, which is vulnerable to XSS. So how do you avoid these attacks? All rules from Reflected XSS apply here. If you want to allow users to use some set of HTML tags, you could use sanitizers such as DOMPurify which will automatically get rid of unwanted tags.


The two types of XSS shown earlier were based on injecting new HTML elements into a page. There is a third way of exploiting XSS by using already existing javascript code.

Let’s look at the online shop application as an example. We’ve modified the design and now offer an input box for adding a URL to an image that will be added somewhere in a page. Users provide a URL, click the preview button, and the image shows in the product description.

Image preview

Figure 9. Image preview

What will happen if instead of URL we provide such string: x onerror=alert(1)? When we submit our new URL the JavaScript code is executed! But how does this happen? When the user clicks the button, the application finds the div container and using its .innerHTML method adds an image tag with URL provided by the user. The renderer doesn’t find an image at the URL, so the onerror method of img is executed, thus invoking XSS code.

This is one of the examples where JavaScript code can be evaluated without injecting any new HTML tags. Another example could be eval function or setTimeout function. The best protection is to not use any of these mechanisms, and if you really need to use one, consider using a sanitiser.

XSS injection via img src attribute

Figure 10. XSS injection via img src attribute

All three examples shown above are highly exaggerated, but its point was to show how each vulnerability works. If you are interested in software security, once again, I highly recommend the book written by Securitum. In the next section, I will describe my experience with software security and my thought process in exploiting vulnerabilities.



Modern front-end frameworks lessen the risk of developing applications that are susceptible to XSS attacks. However, as you can see from  the Google and  Twitter stories mentioned above, the risk still exists. As developers, we must be aware of these problems waiting for us and to broaden our knowledge. I encourage you to read the book mentioned above and to engage with various online courses and challenges that will build to your understanding of cybersecurity.