The short answer
Cross-site scripting (XSS) is a web application vulnerability that lets an attacker run their own JavaScript in another user's browser, because the site places untrusted input in a page without encoding it. The script runs with the site's trust, so it can hijack sessions, change what users see or capture card details typed into a checkout.
On this page
Cross-site scripting (XSS) happens when a web application takes data an attacker controls and puts it into a page without making it safe, so the browser runs it as code. The target is your users, not your server: the script runs on your domain, in their session, with their permissions. Since 2021 the OWASP Top 10 has grouped XSS under Injection, as the current 2025 list still does. For related terms, see the cyber security glossary.
What is an example of cross-site scripting?
Take an online shop whose search page repeats the search term back to the user. A normal search requests /search?q=shoes and the page includes <p>Results for shoes</p> in its HTML.
An attacker sends a customer a link with a script in place of the search term, such as /search?q=<script>alert(document.domain)</script>, URL-encoded so it survives in a link. What happens next depends on whether the page encodes its output:
- Unencoded (vulnerable): the server returns
<p>Results for <script>alert(document.domain)</script></p>, and the browser runs the script on the shop’s domain, inside the customer’s session. - Encoded (safe): the server returns
<p>Results for <script>alert(document.domain)</script></p>, and the browser simply shows the text as part of the search term.
The alert is a harmless proof that testers use. A real attacker would swap it for a script that sends keystrokes or session data to their own server, or rewrites the checkout form. This is reflected XSS. If the shop also saved search terms and showed them to other visitors, for example in a “popular searches” box, the same flaw would become stored XSS.
What are the types of XSS?
The three main types differ in where the payload lives.
| Type | Where the payload lives | How a victim is hit | Typical example |
|---|---|---|---|
| Stored (persistent) | Saved by the application, usually in its database | Anyone who views the affected page | A review, support ticket or profile name that renders script for every viewer |
| Reflected (non-persistent) | In the request, usually a URL parameter | The victim opens a crafted link | A search page that echoes the search term back without encoding |
| DOM-based | Handled only by client-side JavaScript | The page’s own script writes attacker data into the page | Code that reads location.hash and writes it with innerHTML |
Blind XSS is a stored variant that fires where the attacker cannot see it, such as an internal admin console, so the victim is usually a privileged member of staff.
What can an attacker do with an XSS attack?
Whatever the user could do on that page:
- Act as the user, or steal session tokens that scripts can read
- Change the account email or password to take the account over
- Show a fake login prompt on your genuine domain
- Read personal data or admin records displayed on the page
Why does XSS matter on payment pages?
XSS is one route for a card-skimming script to reach an e-commerce checkout. Injected JavaScript can capture card numbers as they are typed, or swap an embedded payment form for a fake one. The card data is stolen even though your servers never store it, and is then used for card-not-present fraud elsewhere.
PCI DSS v4.0.1 tackles this from several directions:
| Requirement | What it expects |
|---|---|
| 6.2.4 | Bespoke and custom software is engineered to prevent common attacks, with cross-site scripting named in the requirement |
| 6.4.2 | Public-facing web applications are protected by an automated solution that detects and prevents web-based attacks (mandatory from 31 March 2025) |
| 6.4.3 | Every script loaded on a payment page is authorised, has its integrity assured and is inventoried with a business or technical justification (mandatory from 31 March 2025) |
| 11.4.1 | Penetration testing includes application-layer testing for, at a minimum, the vulnerabilities listed in 6.2.4 |
| 11.6.1 | A change and tamper detection mechanism alerts on unauthorised changes to the security-impacting HTTP headers and scripts of payment pages as the browser receives them (mandatory from 31 March 2025) |
Which apply depends on how you take payments. Since January 2025, SAQ A omits 6.4.3 and 11.6.1 but requires merchants to confirm their site is not susceptible to attacks from scripts that could affect their e-commerce systems, which an XSS flaw on the page hosting the payment form would undermine. Our guides to SAQ A vs SAQ A-EP eligibility and PCI DSS 6.4.3 and 11.6.1 for e-commerce go further.
How do you prevent cross-site scripting?
Encode output for the context it lands in, and avoid code paths that bypass that encoding. Input validation helps but is not enough, because data that is safe in one context can be dangerous in another.
- Use your framework’s auto-escaping and review every escape hatch, such as
dangerouslySetInnerHTMLin React,v-htmlin Vue or thebypassSecurityTrustfunctions in Angular. - Encode for the context. HTML body, HTML attributes, JavaScript, CSS and URLs each need different encoding.
- Prefer safe DOM APIs such as
textContentoverinnerHTML, and never pass untrusted data toeval()or similar functions. - Sanitise rich text with a maintained library such as DOMPurify where users must be allowed to write HTML.
- Add defence in depth: a strict Content Security Policy and HttpOnly session cookies limit the damage if a flaw slips through.
The OWASP Cross Site Scripting Prevention Cheat Sheet sets out the encoding rules for each context.
How do penetration testers find XSS?
Testers map every input, from URL parameters and form fields to headers, file names and API fields, trace where each comes back out and send payloads built for that context. Stored inputs are followed to every screen that displays them, including back-office tools, and blind payloads call back to the tester if they fire somewhere unseen. DOM-based XSS is found by reading the client-side JavaScript for dangerous sources and sinks.
Automated dynamic application security testing (DAST) finds many reflected cases quickly. Manual web application penetration testing and source code review catch the stored and DOM-based issues that scanners tend to miss.
Why Sovereign Secure?
Our web application and API tests look for XSS by hand as well as with tools, and each finding is confirmed, rated and given a specific fix. As a PCI SSC Qualified Security Assessor company that is also ISO 27001 certified, we show how payment page findings relate to PCI DSS.
Next step: request a penetration testing quote for your website, checkout or API.
Your next step
- Scope your testChoose your test types and asset counts online to scope your penetration test.Scope your test
- Pen testing cost guideUK day rates, price ranges by test type and what drives the cost.Read the cost guide
- Talk to a testerTell us what you need tested. We aim to reply within one working day.Talk to a tester
Last reviewed October 2026 by the Sovereign Secure assessment team.




