XSS (Cross-Site Scripting)

Cross-site scripting (XSS) is a web application vulnerability that allows attacker-controlled code to run in another user’s browser as though it came from a trusted website.

Background

Web browsers use the same-origin policy to separate content from different websites. Pages from one origin generally cannot access protected data belonging to another origin. This boundary helps prevent an unrelated website from reading another site’s session data or acting with its permissions.

An XSS vulnerability weakens that boundary by allowing untrusted code to become part of a trusted application’s page. When the browser receives the page, it may interpret the injected content as legitimate code from the application itself.

The code can then act with the access available to that page and user session. Depending on the application, an attacker may be able to:

  • Read or change information displayed on the page
  • Perform actions through the user’s authenticated session
  • Capture information entered into forms
  • Modify content or display a false login prompt
  • Redirect the user to a malicious website
  • Access browser storage available to the application
  • Target administrators or other privileged users

The term cross-site scripting was introduced around 2000. Early attacks commonly involved content moving between websites, but the meaning later expanded to cover several forms of browser-side code injection.

The abbreviation XSS is used to avoid confusion with CSS, or Cascading Style Sheets.

Types of XSS

XSS vulnerabilities can be classified by whether the malicious input is reflected immediately, stored for later delivery, or processed through client-side code.

Some cases also involve social engineering or changes made by the browser’s parser.

Non-Persistent or Reflected XSS

Reflected XSS occurs when an application receives untrusted input in a request and immediately includes it in the response without handling it safely.

A search page, for example, may display the words entered by a visitor. If the application places that input into the page without context-aware encoding, crafted content may be interpreted as code.

Attackers commonly deliver reflected XSS through a prepared link. A user must usually open the link or submit the manipulated request before the code runs.

The trusted website reflects the attacker’s input, causing the browser to execute it within that site’s context.

Persistent or Stored XSS

Stored XSS occurs when attacker-controlled content is saved and later displayed to users.

The content may be stored in a:

  • Database
  • User profile
  • Comment
  • Support ticket
  • Product review
  • Message
  • Application log

This type can affect anyone who views the stored content. The attacker does not need to send a separate malicious link to every victim.

A single submission can reach many users if the vulnerable page receives regular traffic. Stored XSS may create serious risk when the affected page is viewed by administrators, customer support teams, or users with access to sensitive information.

Server-Side vs. DOM-Based XSS

Server-side XSS occurs when backend application code places untrusted data into an HTML response without the correct output encoding or sanitization. The browser receives a response that already contains the unsafe content.

DOM-based XSS occurs in client-side JavaScript. A script reads attacker-controlled data from a source, such as a URL or browser storage, and passes it to an unsafe DOM function or page element.

In a DOM-based case, the dangerous content may not appear in the original server response. It is introduced or transformed after the page loads.

Testing must therefore examine client-side data flows as well as server output.

Self-XSS

Self-XSS relies on social engineering. An attacker convinces a user to paste or run code in the browser, often by promising access to a feature, reward, account recovery method, or technical fix.

Self-XSS is not usually caused by a vulnerable website accepting and returning attacker-controlled content. The victim executes the code directly.

However, the result can resemble a conventional XSS attack because the code runs in the context of the user’s active browser session.

Organizations can reduce the risk through user education, clear developer-console warnings, and controls that limit the damage available to a compromised session.

Mutated XSS

Mutated XSS, or mXSS, occurs when content that initially appears safe is changed into an unsafe form as the browser parses, repairs, or reconstructs the markup.

This behavior can defeat sanitization that evaluates one representation of the content while the browser ultimately creates another.

Applications that accept rich HTML should use maintained sanitization libraries tested against browser parsing behavior instead of custom filters.

Preventive Measures

No single control prevents every form of XSS. The correct defense depends on where untrusted data enters the page and how the browser will interpret it.

Contextual Output Encoding

Encode untrusted data before placing it into:

  • HTML
  • HTML attributes
  • URLs
  • CSS
  • JavaScript

Each output context has different rules, so one general escaping function is not sufficient everywhere.

Modern frameworks often escape output by default. Developers should understand where those protections apply and avoid bypassing them with functions that render raw HTML.

When ordinary text must be displayed, safe browser APIs such as textContent are preferable to methods that interpret input as markup.

Safely Handling Untrusted HTML

Some applications must accept limited HTML for comments, messages, or formatted content. In those cases, encoding every character would prevent the required formatting from rendering.

Use a well-maintained HTML sanitization library with a restrictive allowlist. The sanitizer should remove unsafe elements, attributes, URLs, and browser execution paths while preserving only the markup the application needs.

Simple blocklists are unreliable because attackers can use alternate elements, encodings, event handlers, and browser parsing behavior. Custom sanitizers are also difficult to maintain safely.

Cookie Security

Secure cookie settings can limit certain consequences of XSS:

  • HttpOnly prevents client-side JavaScript from reading the cookie directly.
  • Secure restricts the cookie to encrypted HTTPS connections.
  • SameSite limits when the browser sends the cookie with cross-site requests.

These attributes do not fix the underlying vulnerability. An injected script may still perform actions through the user’s session even when it cannot read the session cookie.

Limiting Script Execution

A carefully designed Content Security Policy can restrict which scripts, sources, and browser operations are allowed.

A strong CSP can reduce the impact of an XSS vulnerability or prevent certain payloads from running. However, CSP should be used as defense in depth.

It does not replace context-aware output encoding, safe DOM APIs, or HTML sanitization.

Disabling JavaScript entirely can block script execution but is impractical for many modern applications. Security controls should protect users without requiring them to disable essential website functionality.

Modern Defensive Technologies

Trusted Types can help prevent DOM-based XSS by restricting dangerous browser APIs to values created through approved policies.

This makes it harder for an ordinary attacker-controlled string to reach an executable DOM sink.

Static application security testing, dynamic testing, dependency scanning, and manual penetration testing can also identify unsafe data flows.

These controls should be integrated into development and release processes rather than applied only after deployment.

The OWASP Cross-Site Scripting Prevention Cheat Sheet provides detailed guidance for output contexts, sanitization, safe sinks, and supporting controls.

Notable XSS Incidents

XSS vulnerabilities have affected social networks, webmail services, retail sites, government systems, and enterprise applications.

The 2005 Samy worm used a stored XSS weakness on MySpace to modify profiles and spread automatically when other users viewed an infected profile. It showed how stored browser code could move rapidly through a large platform.

In 2018, the British Airways website and mobile application were affected by malicious client-side code that diverted customer payment data. The incident demonstrated the business impact of unauthorized browser-side scripts in a payment environment.

Past incidents do not mean every XSS flaw has the same severity. Risk depends on the affected users, available privileges, accessible information, and actions the application permits.

How Can Organizations Find XSS Vulnerabilities?

XSS testing should cover the entire application lifecycle.

Security and engineering teams should:

  • Map every location where untrusted data enters the application.
  • Review how that data is stored, transformed, and displayed.
  • Use static analysis during development.
  • Run dynamic testing against deployed builds.
  • Test client-side sources and DOM sinks.
  • Add security checks to CI/CD pipelines.
  • Conduct manual penetration testing for complex workflows.
  • Review third-party components and browser-side dependencies.
  • Retest fixes to confirm the root cause was removed.

Automated scanners can identify common patterns, but they may miss vulnerabilities behind authentication, business logic, client-side state, or unusual browser behavior.

Sennovate’s Offensive Security and Exposure Management services include penetration testing across web applications, APIs, mobile applications, cloud environments, and networks.

Frequently Asked Questions About XSS

Is XSS a Client-Side or Server-Side Attack?

The injected code executes in the victim’s browser, making XSS a client-side attack.

The underlying vulnerability may originate in unsafe server-side output, unsafe client-side JavaScript, or both.

Does Input Validation Prevent XSS?

Input validation can reject unexpected data and reduce attack paths, but it cannot prevent every XSS vulnerability.

Applications still need context-aware output encoding, safe DOM APIs, and sanitization where HTML is permitted.

Can a Web Application Firewall Prevent XSS?

A web application firewall can block some known attack patterns.

It may not understand every application context or browser behavior, so it should supplement secure coding and testing rather than replace them.

Is XSS the Same as CSRF?

No. XSS causes attacker-controlled code to run within a trusted application’s browser context.

Cross-site request forgery tricks an authenticated browser into sending an unwanted request. The attacks require different primary defenses.

Can XSS Affect an API?

An API response does not execute code by itself.

XSS can occur when a web application retrieves untrusted API data and inserts it into a browser page through an unsafe output method.

Reduce XSS Risk Across the Application Lifecycle

XSS occurs when untrusted data reaches an executable browser context. Preventing it requires controls that follow the data from input through storage, processing, and final rendering.

Contextual output encoding, reviewed sanitization, safe DOM APIs, cookie protections, CSP, Trusted Types, and continuous testing work together to reduce risk.

The exact combination should reflect how the application handles text, rich content, URLs, scripts, and third-party components.

Sennovate’s Unified Security Engineering services connect application security, cloud security, identity, endpoint protection, and security operations within one engineering program.