31 August 2026

8 XSS Attacks Examples: Code, Impact, and Fixes

Reza Khosravi
No items found.

Table of Contents

8 XSS Attacks Examples: Code, Impact, and Fixes

Most advice on XSS starts in the wrong place. The payload matters, but the failure is usually a broken trust boundary, a value from a URL, database row, browser store, upload, or template context reaching a sink that executes code instead of displaying text. That is why xss attacks examples are easier to understand when they're organized by data flow, not by a grab bag of strings to paste into an alert box.

The same bug can look different in reflected, stored, DOM-based, mutation-based, CSS-adjacent, SVG, second-order, and template-injection cases, because the execution context changes. Read the code samples and scenarios as safe patterns to recognize, not as copy-paste exploits. Every example below follows the same practical lens, source, sink, attack flow, impact, mitigation, and a verification step you can use in code review or testing.

A useful workflow example is DevArmor, because it keeps design decisions, threat models, and pull-request policy aligned while code is moving. That matters more than a one-time scanner result, because XSS often returns through a new parameter, a new rendering path, or a plugin update. For teams trying to keep security context current, that's the difference between an issue that was once fixed and an issue that stays fixed. trusted platform reliability

1. Reflected XSS via URL Parameter Injection

A reflected XSS issue starts when a request parameter goes straight back into the response without safe encoding. The attacker does not need server-side storage, only a link that carries malicious input through a search box, filter, sort key, or similar field. The browser then renders that value as HTML or script in the site's security context.

The classic pattern is easy to recognize in review. A query parameter feeds a page title, search result label, or error message, and the code uses raw DOM insertion or unescaped template output. In practice, phishing works well here, because the victim only has to click a link once.

What the data flow looks like

A URL parameter is the source, the response body is the sink, and the exploit succeeds when the application fails to encode for the exact output context. If the value lands in HTML text, HTML attribute, or JavaScript string context, the right fix changes with the sink. DevArmor's continuous threat modeling is useful here because URL parameters should be reviewed at design time, not after someone finds them in a penetration test, and parameter handling should follow a standard like Java URL encoding guidance.

Practical rule: if the value can come from the address bar, treat it as hostile until the last possible rendering step.

Verification should be boring and deliberate. Inspect the rendered output in browser developer tools, confirm the value is encoded in the right context, and test more than one output location, because one parameter often reaches both visible HTML and hidden JavaScript. Teams that standardize reusable encoding helpers reduce drift, especially when multiple pages reuse the same request parameter handling.

2. Stored XSS via User-Generated Content

Stored XSS becomes dangerous because the payload survives the first request. A comment, profile bio, review, post, or ticket note is saved to the database, then replayed to every viewer who opens that content later. That makes the impact broader than reflected XSS, because the victim does not need to click a malicious link.

The trust mistake is usually obvious in hindsight. Product teams want rich text, emoji, links, and formatting, so they allow user content to pass through with partial filtering or client-side cleanup only. If the server saves unsafe HTML or a dangerous attribute, the browser executes it for anyone who views the page.

The persistence angle is why threat modeling has to map every writable field, not just the public comment form. A shared profile description, support note, admin remark, or moderation queue can all become the execution point. A secure review also has to include older rows already sitting in the database, because fixing the input path does not automatically clean historic data.

Where teams usually miss it

  • Partial sanitization: one endpoint escapes output, another endpoint renders the same field raw.
  • Unsafe rich-text features: linkification, emoji replacement, markdown parsing, or embedded HTML opens a second sink.
  • Stale content: records created before a patch can still carry malicious markup.

A code review should verify that every content endpoint uses the same sanitization policy and that the database never becomes a permanent script storage layer. That is why stored XSS belongs in secure code review, not just in appsec testing. Use the design record and the review trail to force consistency, then validate the output with existing records as well as new submissions. secure code review

3. DOM-Based XSS via JavaScript Event Handlers

A clean server log does not prove the browser is safe. DOM-based XSS can execute entirely in client-side code when a page reads attacker-controlled data from a URL hash, query string, localStorage, sessionStorage, or postMessage, then sends it to a sink such as innerHTML, document.write, an event handler, or script-building logic.

A practical example is a search or preview feature that copies a URL value into an onclick attribute or template string. React, Vue, and plain JavaScript applications face the same risk when helper code bypasses framework escaping or inserts raw HTML. The key question is whether data crosses from a text context into executable markup.

What to inspect in the browser

Use DevTools to trace each value from source to sink. Confirm whether the page reads URL fragments, query parameters, storage APIs, or cross-window messages, then observe how that value enters the DOM. ESLint rules, framework-native rendering, and restrictive Content Security Policy headers reduce exposure only when they are applied consistently.

Verification step: if the content should be text, render it as text, not HTML. If HTML is required, sanitize it before the DOM receives it.

Avoid custom DOM manipulation for user-controlled values. Framework escaping is easier to maintain than string concatenation, while static analysis can flag unsafe patterns before they reach a release branch. See the JavaScript static analysis guidance for patterns to watch for.

The trade-off is controlled flexibility. Raw HTML and dynamic handlers may shorten an implementation, but they expand the execution surface. Test each source-to-sink path with browser-level verification, then add the finding to continuous threat modeling whenever a new event handler, storage input, or rendering helper is introduced.

4. Mutation-Based XSS via Browser HTML Parsing Differences

Mutation-based XSS is a sanitizer mismatch problem. The server thinks it cleaned the input, but the browser reparses malformed HTML and mutates it into something executable. That difference between server parsing and browser parsing is the whole exploit path.

This bug class shows up when a sanitizer is built on assumptions that the browser does not share. Unclosed tags, nested elements, and malformed SVG or style fragments can survive the sanitizer and then turn dangerous after the browser normalizes them. The application looks protected in review, then fails at render time because the final DOM is not the same structure the server believed it was sending.

Why this matters in practice

The defense is not “sanitize harder” in a vague sense. It is using a parsing model that matches the browser, keeping sanitizer libraries current, and testing with known mutation payloads during review. If the sanitizer and browser disagree, the browser wins.

A useful strategy is to keep an internal mutation test suite and run it whenever the sanitizer library changes. That catches regressions introduced by library upgrades, content editor changes, or new markdown features. Teams that rely on HTML input should document which tags and attributes are approved, then verify that the rendered result stays stable after browser parsing.

Browser parsing quirks are not edge cases. They are part of the input model.

Treat any feature that accepts user HTML, markdown, or rich text as a parser boundary. If the boundary is unclear, the attack surface will be unclear too. That is where architecture review, approved sanitization strategy, and library maintenance have to meet.

5. CSS Injection and CSS-Based XSS via Attribute Values

CSS is not supposed to be a scripting layer, but it can still create security problems when user input reaches style attributes, theme editors, or CSS-like configuration fields. The risk rises when applications allow custom class names, background values, font references, or style fragments without strict validation. Even when CSS does not directly execute JavaScript, it can still support data exfiltration, UI redress, or other unsafe behavior.

This is often a product decision first and a security bug second. Teams want user customization, tenant branding, or per-document styling, so they expose a little bit of CSS power and assume the browser will keep the boundary clean. That assumption breaks when attackers control values that affect rendering behavior.

What works and what doesn't

Predefined classes are safer than free-form CSS. A system that allows style-danger or style-success is much easier to defend than one that accepts arbitrary properties or URLs. The same applies to whitelisting allowed properties, because a short allowlist is easier to audit than a giant denylist.

A CSP helps, but it's not a substitute for input controls. Restricting style-src and img-src limits some abuse, yet the application still needs server-side validation of any CSS-like field. Browser DevTools is useful here because it shows the computed style, so you can verify whether an attacker-controlled property was applied.

If a product team needs styling customization, keep the customization surface narrow and documented. Let the UI select from predefined options instead of letting users write rules directly. That trade-off removes flexibility, but it also removes a broad and hard-to-test execution path.

6. SVG and XML-Based XSS via Image Upload and Rendering

SVG is dangerous in upload pipelines because it is XML, not just an image container. If an application accepts user-uploaded SVG files and serves them back with permissive handling, the browser can process embedded script, event handlers, or JavaScript-linked behavior. The file may look like a normal avatar or attachment, but the browser treats it like active content.

This is one of the easiest places for teams to make a mistaken trust decision. Upload validation checks the extension, the preview page renders the file inline, and the application reuses the same domain for user uploads and app pages. That combination turns a file upload into a browser-execution path.

The control set is straightforward, but it has to be consistent across every upload endpoint. Validate file type by content, not only filename, and consider converting user uploads to safer formats when SVG is not essential. Serving user content from a separate subdomain also reduces the blast radius if a file slips through.

Defenses that hold up

  • Centralized validation: one file-checking function for all upload flows.
  • Safe serving location: separate subdomain or isolated storage path for uploads.
  • Preview discipline: do not render active content inline unless the file type is trusted.
  • Logging and review: inspect upload attempts that contain unusual XML structure or script-like tags.

If the business needs SVG, treat it as active content and sanitize it with the same seriousness as HTML. Otherwise, convert it to a safer raster format before preview or download. That is slower than raw passthrough, but it prevents image handling from becoming code execution.

7. Second-Order XSS via Cross-Context Data Flow

Second-order XSS is the bug that appears after a value moves through more than one context. A field may be safe when stored, then unsafe when reused in a dashboard, export, JSON blob, or script literal later. The payload is not necessarily malicious in its first home, but it becomes dangerous when a different renderer interprets it.

Many teams over-focus on the initial input path and under-focus on downstream reuse. A user bio, repository description, support note, or analytics field can be harmless in HTML text, then break out of a JavaScript string or JSON context somewhere else. The mistake is not only missing encoding, it is failing to classify the later context correctly.

What the team has to document

A good design review maps source, storage, and every reuse point. If data enters the app as text and later lands inside a JavaScript literal, it needs JavaScript-safe encoding at the second sink, even if the first sink was already HTML-safe. Context-specific encoding is the point, not generic escaping.

Practical rule: encode for the destination, not for the place where the value was first stored.

Use browser DevTools and repository searches to find where the same field is rendered in more than one layer. That often exposes admin dashboards, export views, or analytics panels that developers did not treat as user-facing attack surfaces. The right verification step is to trace the same field across contexts and confirm each one has the correct encoder or safer rendering primitive.

8. Template Injection Leading to XSS via Expression Language

Template injection crosses from user data into server-side expression syntax. If input is placed inside a template engine without strict boundaries, the application can evaluate attacker-controlled expressions before the response is even built. Depending on the engine and context, the result can be code execution, data exposure, or XSS.

This risk is strongest when teams build dynamic emails, notification templates, support workflows, or content personalization without hard separation between template syntax and user content. A search box, form field, or workflow variable that gets interpolated into a template engine is not just text anymore. It is code-like input moving into a code-like parser.

Static analysis helps because this bug often leaves a recognizable trail in the source. Search for direct interpolation into template strings, then verify whether auto-escaping is on by default and whether dangerous expression features are disabled. Testing with harmless probe expressions during review can reveal whether input is treated as data or executed as syntax.

What should be locked down

  • Auto-escaping: keep it enabled in every supported template engine.
  • Safe templates only: avoid constructing templates from user input.
  • Restricted features: disable introspection and advanced expression features unless absolutely required.
  • Security review of workflows: email generators, admin tools, and user-facing builders need the same scrutiny.

Template injection is especially risky because teams often assume the server side is safer than the browser. It isn't. A server parser that consumes user input as syntax can create the same class of trust failure, just one layer earlier.

8 XSS Attack Examples Compared

VariantComplexity 🔄Resources & Skill ⚡Expected Impact 📊 ⭐Typical Targets / Ideal Use CasesKey Advantages / Quick Tips 💡
Reflected XSS via URL Parameter InjectionLow → Moderate, single-request reflection; easy to craftLow, basic scripting and phishing/social engineeringMedium, targeted account/session theft, requires user clickSearch/redirect/query params; links shared via email/chatEasy to exploit/demonstrate; mitigate with strict input validation, output encoding, CSP
Stored XSS via User-Generated Content (Comment/Post Field)Moderate, requires persistence and storage flowsLow → Moderate, submit payloads and monitor resultsHigh, persistent, affects all viewers, high scale impactComments, posts, profiles, reviews, forumsHigh attacker ROI due to persistence; enforce server/client sanitization, allowlists (DOMPurify), content audits
DOM-based XSS via JavaScript Event HandlersModerate, entirely client-side, subtle code patternsModerate, requires JS/SPA knowledge and DOM analysisMedium → High, bypasses server defenses; affects SPA userslocation.hash, queryString, localStorage, client-side DOM sinks (innerHTML)Hard for WAFs to catch; avoid innerHTML, use textContent/createElement, trusted types, ESLint checks
Mutation-based XSS (mXSS) via Browser HTML Parsing DifferencesHigh, exploits parser normalization and sanitizer mismatchHigh, needs deep sanitizer + browser parsing knowledge and testingHigh (targeted), can bypass mature sanitizers, browser-specificHTML sanitizers, SVG/style inputs, any stored HTML contentBypasses naive sanitizers; use robust/updated sanitizers, server+client parsing with HTML5 parser, test known mXSS payloads
CSS Injection / CSS-based XSS via Attribute ValuesLow → Moderate, styling context abuse, often subtleLow, craft CSS payloads or malicious class namesLow → Medium, exfiltration possible (logs), relies on browser quirksstyle attributes, theme inputs, email clients, custom CSS fieldsEvades tag-focused filters; disallow user styles, whitelist CSS props, enforce strict CSP style-src
SVG/XML-based XSS via Image Upload and RenderingModerate, file-upload pipeline and rendering contextLow → Moderate, create malicious SVGs, exploit upload flawsHigh, auto-rendered images can execute scripts broadlyImage uploads, profile avatars, file previews, document embedsHigh success rate vs naive filters; validate magic bytes, convert to safe formats, serve uploads from separate domain, strip scripts
Second-Order XSS via Cross-Context Data FlowHigh, multi-step data-flow vulnerability across contextsHigh, requires mapping storage → various output contextsHigh, stealthy, payload may lie dormant then execute in different contextMicroservices, analytics/admin dashboards, JS string interpolationOften missed by tests; apply context-specific encoding at use, map data flows, use JSON serialization
Template Injection leading to XSS / SSTIHigh, server-side template parsing can allow expressions/RCEHigh, deep knowledge of template engine required; potential RCEVery High, can lead to XSS and RCE, full server compromiseEmail/report templates, dynamic template rendering, PDF generationCan escalate to RCE; never interpolate raw user input into templates, use sandboxed envs, disable introspection and use allowlists

Turn XSS Examples Into Enforced Controls

The recurring pattern is consistent across every one of these xss attacks examples. Find every untrusted source, classify the output context, and use a safe framework primitive or context-specific encoding for that destination. Sanitize only where HTML is required, isolate uploads, and add CSP as defense in depth, not as a primary fix. The OWASP history of XSS shows why this keeps coming back, and the long-running placement of XSS in guidance since 2003, including its appearance at #1 in 2007, #2 in 2010, and #3 in 2013 and A03:2021 Injection, is a reminder that this is a durable application-security problem, not a dated browser quirk. OWASP XSS guidance

The same practical controls should show up in review artifacts, not just in slide decks. During design review, map the source to the sink. During implementation, trace the data flow in code and in the browser. During testing, run payloads that are safe in one context and dangerous in another, and check sanitizer updates when dependencies change. During pull request review, block changes that introduce new raw sinks, new upload surfaces, or new template interpolation paths.

A compact verification routine helps teams stay honest. Confirm that URL parameters are encoded for the exact response context, that stored user content is never rendered raw, that DOM writes use safe APIs, that uploaded SVG or XML content is isolated or converted, that second-order uses are encoded for the final context, and that template engines are auto-escaping by default. Then verify the browser result, not just the source code, because XSS is a rendering problem as much as a coding problem.

That is where a living workflow matters. DevArmor fits naturally when teams want threat models, design decisions, and policy enforcement to stay attached to tickets, repositories, and PRs instead of drifting into stale documents. A system like that can keep XSS controls visible across planning, coding, and review, which is exactly where these bugs need to be stopped. cyber security shield explained


If your team is trying to keep XSS controls from slipping between design and merge, DevArmor can keep the security context attached to the work itself. Visit DevArmor to see how continuous threat modeling, design reviews, and Policy-as-Code enforcement can help teams catch unsafe data flows before they ship.

Table of Contents

Subscribe