Q6 of 24 · Security
What is cross-site scripting (XSS) and how do you test that an application prevents it?
Short answer
Short answer: XSS occurs when user-supplied content is rendered in the browser without encoding, allowing injected JavaScript to execute in another user's session. Test by submitting XSS payloads in text inputs and stored fields, then verify the payload is HTML-encoded in the output — not executed as a script.
Detail
Three types with different test approaches:
Reflected XSS: the payload is in the request (URL parameter, form field) and echoed back in the response. Test by submitting <script>alert(1)</script> or <img src=x onerror=alert(1)> in URL parameters and form fields. The response should contain the encoded form (<script>) not the literal tag — and no alert should fire.
Stored XSS: the payload is saved to the database and later rendered for other users. Test by saving a XSS payload in a user-supplied field (comment, username, address), then loading the page where that content is displayed. If the alert fires, the content is being rendered unencoded.
DOM-based XSS: the payload never reaches the server — it's processed by client-side JavaScript that reads from location.hash, document.referrer, or localStorage and writes to innerHTML or similar sinks. Test by crafting URLs with payloads in the fragment identifier (#<img src=x onerror=alert(1)>) and observing whether the script executes.
Testing approach: use a diverse set of payloads because simple payloads are commonly blocked while more obscure ones are not. Test both the content-type of the response (HTML vs JSON — JSON responses should have Content-Type: application/json, preventing the browser from rendering them as HTML) and the actual rendered output. CSP violations in the browser console are a signal that a payload was attempted even if blocked.
// EXAMPLE
xss.test.ts
const xssPayloads = [
'<script>alert(1)</script>',
'<img src=x onerror=alert(1)>',
'"><svg onload=alert(1)>',
];
for (const payload of xssPayloads) {
await page.goto(`/search?q=${encodeURIComponent(payload)}`);
// The rendered page should show encoded text, not execute the script
const bodyText = await page.locator('body').innerText();
expect(bodyText).not.toContain('alert(1)'); // if executed, would have run
const bodyHTML = await page.locator('body').innerHTML();
expect(bodyHTML).not.toContain('<script>'); // must be encoded
}