# What is cross-site scripting (XSS)?

Canonical: https://hackergpt.org/learn/xss/

**Cross-site scripting (XSS) is a vulnerability where an application puts untrusted input into a web page without encoding it, so the browser runs it as script. The script runs as the victim, on the vulnerable site, and can read the page, act with the victim's session or change what they see.**

## Why it matters

XSS is CWE-79, and the OWASP Top 10:2025 counts it under A05, injection. It matters because the browser cannot tell your script from the injected one: both arrive from your domain, so the injected code gets the same access to the page, its forms and any session data that script can reach.

OWASP describes three kinds. Reflected XSS bounces input from the request straight back into the response. Stored XSS saves it, in a comment or a profile name, and serves it to every later visitor. DOM-based XSS happens entirely in the browser, when front-end code writes input into the page with an API such as innerHTML.

## Example: the same template, unsafe and safe

Suppose your app (https://your-app.example) greets a user by the name they chose. The first line writes the name into the page as HTML, so markup in the name becomes part of the page. The second writes it as text, so the browser shows the characters and runs nothing:

```
// Unsafe: the name is parsed as HTML
greeting.innerHTML = "Hello, " + user.name;

// Safe: the name is inserted as text
greeting.textContent = "Hello, " + user.name;
```

Frameworks such as React escape text by default, which is why XSS in them usually comes from the escape hatches: dangerouslySetInnerHTML, rendering Markdown to HTML without sanitizing it, or putting user input into an href. To check your own app, search the code for those, then enter a harmless marker with angle brackets, such as <b>test</b>, into each field that is shown back to users. If it renders bold anywhere, that output is not encoded. CyberGym, the legal practice target, has XSS challenges for seeing the full bug class on a site that permits it.

## Common mistakes

- **Filtering input instead of encoding output.** Block-lists of tags miss variants. Encode for the context where the data is written: HTML, attribute, URL or JavaScript.
- **Trusting data from your own database.** Stored XSS arrives from your database. Anything a user once typed is still untrusted.
- **Treating a Content Security Policy as the fix.** CSP limits the damage when it is strict; the bug is still the missing encoding.
- **Forgetting URLs.** A link whose href comes from a user can carry a javascript: URL. Allow only http and https.

## Related terms

- [SQL injection](https://hackergpt.org/learn/sql-injection/)
- [Security headers](https://hackergpt.org/learn/security-headers/)
- [OWASP Top 10](https://hackergpt.org/learn/owasp-top-10/)
- [Deliberately vulnerable app](https://hackergpt.org/learn/deliberately-vulnerable-app/)

## Go deeper

- [Security checklist for vibe-coded and indie SaaS apps](https://hackergpt.org/blog/vibe-coded-app-security-checklist/)
- [How to pentest your own website with an AI agent](https://hackergpt.org/blog/how-to-pentest-your-own-website/)
- [HackerGPT features: test your own site and learn why each finding matters](https://hackergpt.org/features/)

## Sources

- [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
- [OWASP: Cross Site Scripting (XSS)](https://owasp.org/www-community/attacks/xss/)
- [OWASP Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
- [OWASP Top 10:2025 A05 Injection](https://top10.owasp.org/2025/A05_2025-Injection/)

Test only sites you own or have written permission to test. To practise without one, use CyberGym, a legal, deliberately vulnerable target. [Practise on CyberGym](https://cybergym.hackergpt.app).
