What is Cross-Site Scripting?
Cross-site scripting (XSS) attacks are a type of injection in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser-side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.How XSS Occurs
Cross-site scripting involves injecting malicious code into an otherwise safe website. It is usually done through user input that is not sufficiently sanitized before being processed and stored on the server. Malicious code can be inserted into the codebase through:- Lack of Code Reviews: Code is accidentally inserted without proper security review
- Internal Threat Actor: Intentional insertion by malicious insider
- SQL/XSS Injection Exploit: Vulnerability exploited to insert malicious scripts
Vulnerable Code Patterns
Students should be able to identify that a script referring to a foreign context has been executed or that a POST request has been made to an unknown URL.
Example 1: External Script Loading
Malicious External Script
Example 2: Data Exfiltration
Malicious POST Request
Vulnerable Code in Normo Unsecure PWA
The application has an XSS vulnerability in how it handles feedback display:Unsafe HTML Rendering (templates/partials/success_feedback.html)
user_management.py:55-59
Flask Template Rendering (templates/index.html:30)
templates/index.html
|safe filter in Flask/Jinja2 tells the template engine not to escape HTML, making it vulnerable to XSS if msg contains user-controlled data.
How to Test for XSS
Test Basic Script Injection
Paste this into any input box or after the URL in the browser address bar:If an alert box appears, the application is vulnerable to XSS.
Test Image-Based XSS
Try this payload:This doesn’t rely on
<script> tags and may bypass naive filters.Exploitation Examples
Example 1: Cookie Theft
Example 1: Cookie Theft
Example 2: Credential Harvesting
Example 2: Credential Harvesting
Attack Vector: Inject a fake login form:Result: Users see a fake login form that sends credentials to the attacker.
Example 3: Keylogging
Example 3: Keylogging
Attack Vector: Install a keylogger:Result: Every keystroke is sent to the attacker’s server.
Example 4: CSRF Token Theft
Example 4: CSRF Token Theft
Attack Vector: Steal CSRF tokens to perform privileged actions:Result: Attacker can perform actions on behalf of the victim.
How to Fix XSS Vulnerabilities
The key to preventing XSS is to always sanitize and escape user input before rendering it in HTML, JavaScript, or URLs.
Secure Implementation
Countermeasures
Regular Code Reviews
Conduct regular security-focused code reviews looking for:
- Use of
|safefilter in templates - Direct HTML construction from user input
- External script sources
- Unvalidated URLs in script tags
Secure Third-Party Libraries
- Only known and secure third-party libraries should be externally linked
- Preferably, after a code review, third-party libraries should be locally served
- Monitor 3rd party libraries for known vulnerabilities
- Patch vulnerabilities immediately upon discovery
Declare Character Encoding
Always declare the character encoding in your HTML:This prevents certain encoding-based XSS attacks.
Implement Content Security Policy (CSP)
Add a Content Security Policy header to block inline scripts and restrict script sources:This blocks
<script> and <svg> tags from untrusted sources.Use Framework Security Features
Modern frameworks have built-in XSS protection:
- Flask/Jinja2: Automatic HTML escaping (don’t use
|safeunless necessary) - React: Automatic escaping in JSX
- Angular: Built-in sanitization
Testing Checklist
Input Fields to Test
Input Fields to Test
Test XSS in all areas that accept user input:
- ✅ Login forms (username and password fields)
- ✅ Registration forms
- ✅ Feedback/comment forms
- ✅ Search boxes
- ✅ Profile update fields
- ✅ URL parameters
- ✅ HTTP headers (User-Agent, Referer)
Types of XSS to Test
Types of XSS to Test
- Stored XSS: Payload is saved to database and executed when viewed
- Reflected XSS: Payload is immediately reflected in response
- DOM-based XSS: Payload executes through client-side JavaScript
File Locations
Line 58: Vulnerable feedback rendering without HTML escapingThe
listFeedback() function writes user-submitted feedback directly to HTML without sanitization.Line 30: Vulnerable template rendering with
|safe filterThe |safe filter disables Jinja2’s automatic HTML escaping, creating an XSS vulnerability if msg contains user-controlled data.