Login
ChallengesLearn
Scoreboard
Teams
Profile

Preferences

Truesapiens

LearnCross Site ScriptingContext-Based XSS Escapes
Cross Site Scripting·Lesson 8 of 12

Context-Based XSS Escapes

HTML entity context, JS string context, URL context, CSS context. Each context demands a different escape sequence — the attacker finds one; the defender must close all of them.

Advanced15 min
XSSContextEscaping
Loading lesson…
PreviousBlind XSSNextCSP Bypass Techniques

© 2026 Truesapiens.

Terms of ServicePrivacy PolicyCookie Policy

A single escaping strategy does not work everywhere. The characters that are dangerous in an HTML element body are different from the ones that break a JavaScript string. A URL context forbids javascript:protocols, which are perfectly safe in CSS. Understanding how the browser parses each context — and choosing the correct escape for each — is the difference between a secure application and one that fails to a creative payload.

What you'll be able to do
  • Identify the four primary injection contexts: HTML, JavaScript, URL, and CSS.
  • Apply the correct escaping scheme for each context.
  • Explain how injection boundaries shift when input moves between contexts.
  • Recognise the OWASP XSS Filter Evasion Cheat Sheet as a living reference.
Key terms
HTML element context
User input placed between HTML tags. Raw < and > create new elements. Escape < > & " ' as HTML entities.
JavaScript string context
Input placed inside a quoted JavaScript string. Quotes and backslashes break the string boundary. Escape using \n \t \" and unicode escapes.
URL context
Input placed in href, src, or action attributes. The javascript: and data: protocols can execute code. Validate protocol before encoding.
CSS context
Input placed in style attributes or CSS values. url() invokes HTTP requests and expression() (legacy IE) evaluates JS. Use CSS-escaping and whitelist properties.
What is it?

Four contexts, four escape strategies

When a web application inserts user-supplied data into a page, the data lands in one of four parsing contexts. The browser has different parsing rules for each:

  • HTML element body — between tags. The characters < and > open and close elements. HTML entity encoding is the correct defence.
  • HTML attribute— inside a tag's attribute. The quote character (single or double) closes the attribute value, and > can close the tag silently. HTML entity encoding works, but attribute-specific validation (e.g. blocking event handlers) is also needed.
  • JavaScript string — inside a<script> block or an event handler. The quote character and backslash are dangerous. JavaScript string escaping (backslash escapes) plus unicode escapes for non-ASCII is the correct approach.
  • URL — inside href, src, or action. The javascript: protocol executes JS. Protocol whitelisting plus URL encoding is required.
  • CSS — inside a style attribute or CSS value. CSS escaping prevents injection, but url() callbacks still leak data.
htmlsafe
<!-- HTML element context → entity encode < > & -->
<div>USER_INPUT escapes to &amp;lt;img src=&amp;gt;</div>

<!-- JavaScript string context → backslash-escape quotes and newlines -->
<script>var x = "USER_INPUT escapes to \" + \n + \t";</script>

<!-- URL context → protocol whitelist + URL-encode -->
<a href="USER_INPUT esc. to https%3A%2F%2Fsafe.com">link</a>

<!-- CSS context → CSS-escape hex values -->
<style>.cls { color: USER_INPUT\000020escaped }</style>
Context injection points
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

Context visualiser

Select a context and type in some input. The visualiser highlights the injection boundary — the exact point where your input enters the HTML template. Toggle context-aware escaping to see how the characters change when properly encoded for that specific context.

context-labstaging
context-lab · injection visualiser
HTML element

Input lands between HTML tags. Raw < and > create new elements.

Template with injection boundary
<div class="content"> (input) </div>
Submit input to see the injection boundary in action.
Recommendation: Encode < > & " ' as HTML entities.
html
<div class="content">
  <span class="text-ink-subtle/60">(your input)</span>
</div>
Real-world relevance

The OWASP XSS Filter Evasion Cheat Sheet

The OWASP XSS Filter Evasion Cheat Sheet is the definitive living document that catalogs context-specific injection techniques. It documents payloads for every parsing context and tracks how browsers and sanitizers evolve around them. As browser vendors patch one vector, researchers document a new one, and the cheat sheet expands. It currently contains dozens of distinct payload classes, from basic HTML entity bypasses to esoteric SVG namespace injections that only work in specific browser versions.

The cheat sheet's existence underscores a fundamental truth: context-aware escaping is not a one-time fix but an ongoing discipline. Each new browser version, each new HTML specification feature (like<template> orShadowDOM), and each new framework introduces new parsing behaviours that an attacker can exploit if the defender is not encoding correctly for the specific context.

Mitigation

Context-aware escaping in practice

Most modern frameworks provide context-aware escaping automatically. React's JSX escapes HTML element and attribute contexts by default. Vue's template syntax does the same. The danger arises when developers opt out: dangerouslySetInnerHTML in React, v-html in Vue, andinnerHTML in vanilla JS. Each opt-out must be audited to ensure the data is either safe or correctly escaped for its target context.

For server-side templates, libraries like OWASP Java Encoder and Microsoft AntiXSS provide context-specific encoding functions. The guiding principle is: never concatenate user input into any structured language (HTML, JS, CSS, URL) without using a context-aware encoder.

javascriptvulnerable
// VULNERABLE - generic escaping for all contexts
function escape(input) {
  return input.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// This does NOT protect inside a JavaScript string!

// SAFE - context-specific escaping
function escapeJsString(input: string): string {
  return input
    .replace(/\\/g, '\\\\')
    .replace(/"/g, '\\"')
    .replace(/'/g, "\\'")
    .replace(/\n/g, '\\n')
    .replace(/\r/g, '\\r');
}

function escapeUrl(input: string): string {
  const allowed = ['http:', 'https:'];
  try {
    const url = new URL(input);
    if (!allowed.includes(url.protocol)) return '#';
    return encodeURI(input);
  } catch { return '#'; }
}
Further reading
  • OWASP XSS Filter Evasion Cheat Sheet(OWASP)
  • OWASP Java Encoder Project(OWASP)
  • CWE-79: Improper Neutralization of Input During Web Page Generation(MITRE)
Key takeaways

What to remember

  • There are four primary HTML injection contexts: element body, attribute, JavaScript string, and URL — each with different dangerous characters.
  • HTML entity encoding is only correct for element and attribute contexts. It does not protect inside JavaScript or URL contexts.
  • JavaScript context requires backslash escaping; URL context requires protocol validation + URL encoding; CSS requires CSS-specific hex escaping.
  • Modern frameworks escape by default — audit each dangerouslySetInnerHTMLor v-html usage.
  • The OWASP XSS Filter Evasion Cheat Sheet is the canonical reference for context-specific payloads and defences.

Knowledge check

0/3 answered · 0 correct
  1. 1.Which escaping scheme is correct for user input placed inside a JavaScript string literal?

  2. 2.Why is HTML entity encoding insufficient for a URL (href) context?

  3. 3.What is the purpose of the OWASP XSS Filter Evasion Cheat Sheet?