Skip to content
SDETRole
SDETRole

Glossary · Security

Cross-site scripting

Also called: XSS, cross site scripting, stored XSS, reflected XSS

Definition

XSS is a vulnerability where untrusted input is rendered as executable script in another user's browser, letting an attacker act as that user.

Cross-site scripting (XSS) happens when an application takes input from one user and puts it into a page without proper encoding, so the browser treats it as HTML or JavaScript instead of text. The script then runs with the victim’s session on the vulnerable site: it can read page data, make requests as the user or change what they see. In the OWASP Top 10 2021 it is grouped under A03 Injection.

The three types

  • Stored. The payload is saved (a comment, a profile name, a support ticket) and served to everyone who views it. Usually the most serious.
  • Reflected. The payload is in the request, often a URL parameter such as a search term, and echoed straight back in the response.
  • DOM-based. Client-side JavaScript reads attacker-controlled data (for example location.hash) and writes it into the page with an unsafe sink such as innerHTML.

What a tester checks

Put a harmless marker into every field that is later displayed (to you, to other users, to admins in a back office) and see whether it comes back as text or as live markup. An automated check in Playwright, for authorised testing only:

import { test, expect } from '@playwright/test';

test('comment body is rendered as text, not HTML', async ({ page }) => {
  const probe = '<img src=x onerror="window.__xssProbe=1">';

  await page.goto('/posts/1');
  await page.getByLabel('Comment').fill(probe);
  await page.getByRole('button', { name: 'Post comment' }).click();

  // Escaped output shows the literal characters on screen
  await expect(page.getByText(probe)).toBeVisible();
  // and the handler never ran
  expect(await page.evaluate(() => (window as any).__xssProbe)).toBeUndefined();
});

Also check output contexts beyond plain HTML: values inside attributes, inside inline scripts, in URLs (javascript: links) and in rich-text editors, because each needs different encoding.

Defences to verify

  • Output encoding by default. Modern frameworks (React, Angular, Vue) escape text automatically; look for the escape hatches such as dangerouslySetInnerHTML, v-html or innerHTML.
  • HTML sanitisation for features that genuinely accept markup.
  • A Content Security Policy header that blocks inline scripts, as a second layer.
  • HttpOnly session cookies, so a successful XSS cannot simply read the session cookie.

Never test on systems you do not own or lack written permission to test.

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →