What Is Cross Site Scripting? Types, Risks and How to Prevent It

by Rebecca Sutton

Cross site scripting (XSS) is a flaw that lets an attacker run their own JavaScript inside your website, in the browser of anyone who visits it. The browser trusts the script because it appears to come from your site. That trust is what the attacker abuses. OWASP describes it as a type of injection in which malicious scripts are injected into otherwise benign and trusted websites.

This guide explains how the attack works, the three main types, what it can cost a business, and how to fix it. It is written for IT managers and business owners, not developers.

Web page source code open on a laptop, where cross site scripting flaws hide

How does cross site scripting work?

Most websites take input from users: a search box, a comment form, a profile name, a URL parameter. XSS happens when the site puts that input back into a page without making it safe first. The browser cannot tell the difference between the site’s own code and the attacker’s text, so it runs both.

Imagine a search page that prints “You searched for” followed by whatever the visitor typed. If an attacker types a snippet of script instead of a search term, and the page prints it as is, the script runs. The MDN web docs give this exact pattern as an example of unsafe server-side rendering.

What are the three types of XSS?

OWASP groups XSS attacks into three types. They differ in where the malicious script lives and when it fires.

Reflected XSS

The script is bounced off the server in a response such as an error message or a set of search results. The attacker needs the victim to click a crafted link, so these attacks usually arrive by email or message. Nothing is saved on the server.

Stored XSS

The script is saved on the server, for example in a comment, a forum post or a database field. Every visitor who loads that content runs the script. Stored XSS is usually the more dangerous type, because the victim does not need to click anything unusual.

DOM-based XSS

The flaw sits in the page’s own JavaScript. Client-side code takes untrusted data, such as part of the URL, and writes it into the page unsafely. The server may never see the payload at all, which makes this type easy to miss in server logs.

Type Where the script lives Victim action needed
Reflected In a link, bounced back by the server Click a crafted link
Stored Saved on the server Just visit the page
DOM-based Built in the browser by page code Usually a crafted link

What can an attacker do with XSS?

Once their script runs, the attacker acts as the user. MDN notes that an attacker can read and change everything on the loaded page and in local storage, and can make requests using the victim’s credentials. OWASP lists a wider set of outcomes:

  • Session hijacking through cookie theft
  • Unauthorised access to accounts
  • Disclosure of sensitive files
  • Installing malware
  • Changing what the page displays
  • Redirecting visitors to a site the attacker controls

For a business, the worst case is an XSS bug in an admin panel or customer portal. A stored script that runs when a staff member opens a support ticket can act with that person’s privileges. That can turn a small input-handling mistake into a full account takeover.

Is a brochure website at risk?

Yes. Cross site scripting does not need a big application behind it. OWASP specifically calls out the belief that a read-only or brochureware site is safe from serious reflected XSS as a myth. If the site reflects any input, such as a search box or a URL parameter in an error page, the risk exists. The damage lands on your visitors, and on your reputation.

Where does XSS sit in the OWASP Top 10?

In the 2021 edition, XSS was folded into the A03 Injection category. The OWASP entry lists CWE-79 (XSS) among the main weaknesses in that group and reports that 94% of the applications tested were checked for some form of injection. It is still one of the most common findings in web security assessments.

How do you prevent cross site scripting?

No single control solves it. The OWASP prevention cheat sheet stresses layered defences. In order of importance:

  1. Encode output for its context. Characters such as < and > must be converted to harmless entities before they are placed in HTML. HTML, attributes, JavaScript, CSS and URLs each need their own encoding rules.
  2. Use a framework that escapes by default. Django and React JSX encode output automatically. Watch the escape hatches, such as React’s dangerouslySetInnerHTML and Angular’s bypassSecurityTrustAs* functions, because they switch that protection off.
  3. Sanitise any HTML users are allowed to write. A maintained library such as DOMPurify strips dangerous elements. Keep it patched, because browsers keep changing.
  4. Add a strict Content Security Policy. MDN says a strict policy using nonces or hashes can stop injected scripts from running. OWASP treats it as a second line of defence, not a replacement for fixing the code.
  5. Consider Trusted Types. This browser feature throws an error when unsanitised strings reach risky APIs such as innerHTML or eval().

Cookie settings such as HttpOnly can also limit what a stolen script can reach. They do not stop the script running, so treat them as damage control.

How do you find XSS in your own applications?

Automated scanners catch the obvious cases. They struggle with stored XSS that fires on a different page, DOM-based flaws buried in JavaScript, and bugs that only appear after login. A manual test follows user input through the application, tries payloads in every context where it is reflected, and checks whether your defences hold up. Our web application penetration test covers this as standard, and a secure code review can find the unsafe patterns at source.

If you are not sure where your exposure is, get in touch and we will talk through what a scoped test would involve.

What should you do this week?

Start small. List every place your site or portal accepts input and shows it back to someone. Ask your developers whether output is encoded by default and where it is not. Check that a Content Security Policy is in place on your most sensitive application. Those three answers will tell you quickly how exposed you are.

Frequently asked questions

Is XSS the same as SQL injection?

No. Both are injection flaws, but SQL injection targets your database, while XSS targets your users’ browsers. They have different fixes: parameterised queries for SQL, output encoding for XSS.

Can XSS steal passwords?

It can, in several ways. A script can read what a user types into a form on the page, steal session data, or show a fake login box. That is why one bug can lead to account takeover.

Does HTTPS prevent XSS?

No. HTTPS protects data in transit. An XSS script runs inside the page after it has arrived, so encryption does not help.

Do WordPress sites get cross site scripting flaws?

Yes, usually through plugins and themes that fail to encode output. Keep them updated and remove the ones you do not use.

How often should we test for it?

Test after major releases and at least once a year. New features that accept input are the most likely source of new flaws. Ask your testers to report where input is reflected and how each case was checked, so your developers can fix the cause and not just the single page.

Subscribe to our newsletter

Honest updates, straight to your inbox. Unsubscribe any time.

You may also like