HTML Entity Encoding: What It Is and How It Prevents XSS
HTML entities like &, <, and > aren't just formatting quirks — they're the first line of defense against cross-site scripting attacks. This guide covers the full entity system and why output encoding matters.
If you've ever viewed the source of a web page and seen & where an ampersand should be, or < where a less-than sign should be, you've seen HTML entities in action. They look like encoding artifacts — and in a sense they are — but they serve a purpose that goes far beyond display correctness. HTML entity encoding is the mechanism that prevents your browser from interpreting data as code, and it's the primary defense against one of the most common and dangerous web security vulnerabilities: cross-site scripting (XSS).
This article explains what HTML entities are, the full syntax for named, decimal, and hexadecimal entities, the five characters you must always encode, and how proper output encoding prevents XSS attacks.
What Are HTML Entities?
An HTML entity is a sequence of characters that represents a single character in an HTML document. Entities exist because certain characters have special meaning in HTML syntax — the less-than sign starts a tag, the ampersand starts an entity reference, and the greater-than sign ends a tag. If you want to display these characters as literal text rather than having the browser interpret them as HTML markup, you must use their entity equivalents.
HTML entities come in three forms.
Named entities use a human-readable name: & for the ampersand, < for the less-than sign, > for the greater-than sign, " for the double quote, and ' for the single quote. The HTML specification defines over 2,200 named entities, covering everything from accented letters (é for the accented e) to mathematical symbols (∞ for the infinity symbol) to arrows (→ for the rightward arrow). The HTML Living Standard maintains the complete list.
Decimal numeric entities use the character's Unicode code point in decimal: & for the ampersand (code point 38), < for the less-than sign (code point 60), € for the Euro sign (code point 8364). Any Unicode character can be represented this way, even if it doesn't have a named entity.
Hexadecimal numeric entities use the code point in hexadecimal, prefixed with x: & for the ampersand (hex 26), < for the less-than sign (hex 3C), € for the Euro sign (hex 20AC). This form is often preferred by developers because Unicode code points are conventionally written in hexadecimal (U+0026, U+003C, U+20AC).
All three forms are equivalent. The browser decodes them to the same character. Our HTML encoder converts text to its entity-encoded form, and the HTML decoder reverses the process.
The Five Critical Characters
While HTML defines thousands of entities, five characters are critical because they have syntactic meaning in HTML. Failing to encode these when they appear in user-provided content is the root cause of most XSS vulnerabilities.
The ampersand — encoded as &. The ampersand starts every entity reference. If not encoded, the browser may try to interpret the following characters as an entity name, leading to display errors or, in pathological cases, character injection.
The less-than sign — encoded as <. This character opens an HTML tag. If user input containing a less-than sign followed by a tag name like script is inserted into a page without encoding, the browser interprets it as an actual script tag and executes whatever JavaScript follows. This is the classic XSS vector.
The greater-than sign — encoded as >. This character closes an HTML tag. While encoding the greater-than sign is less strictly necessary than encoding the less-than sign (a greater-than sign without a matching less-than sign is usually harmless), best practice is to always encode it for consistency and to prevent edge-case parsing issues.
The double quote — encoded as ". Inside a double-quoted HTML attribute value (like href="..." or value="..."), an unencoded double quote terminates the attribute. An attacker can inject additional attributes — including event handlers like onmouseover — by including a double quote in their input.
The single quote — encoded as ' or '. Same risk as double quotes, but for single-quoted attribute values. Note that ' was not defined in HTML 4 (only in XML/XHTML), so ' is the more compatible form.
If you do nothing else, encoding these five characters in all user-provided content before inserting it into HTML will prevent the vast majority of XSS attacks. Our HTML encoder encodes all five by default.
Cross-Site Scripting (XSS): The Attack
Cross-site scripting is consistently ranked among the most critical web security vulnerabilities. The OWASP Top 10 has included injection vulnerabilities (of which XSS is a subtype) in every edition since its inception. XSS occurs when an attacker injects malicious scripts into content that's served to other users.
The attack works like this. A web application accepts input from a user — a comment, a profile name, a search query, a URL parameter — and later displays that input on a page without proper encoding. If the input contains HTML or JavaScript, the browser executes it in the context of the vulnerable site. The attacker's script then has access to the victim's cookies, session tokens, and DOM — it can steal credentials, redirect the user, modify the page content, or perform actions on behalf of the user.
There are three types of XSS. Stored XSS (also called persistent XSS) occurs when the malicious input is saved to the server (in a database, file, or cache) and served to every user who views the affected page. A classic example is a comment system that doesn't encode HTML in comments — an attacker posts a comment containing a script tag, and every visitor to that page executes the script. Reflected XSS occurs when the malicious input is included in a URL (typically a query parameter) and reflected back in the page's response. The attacker crafts a malicious URL and tricks a victim into clicking it. DOM-based XSS occurs entirely in the browser — the server never sees the malicious payload. Client-side JavaScript reads user input (from the URL fragment, document.referrer, postMessage, etc.) and inserts it into the DOM without encoding.
All three types are prevented by the same fundamental principle: encode all untrusted data before inserting it into HTML.
Output Encoding: The Defense
The OWASP XSS Prevention Cheat Sheet defines output encoding as the primary defense against XSS. The principle is: every time you insert untrusted data into an HTML document, encode it for the specific context where it's being inserted.
HTML body context — when inserting data between HTML tags (for example, inside a paragraph element), encode the five critical characters. A string containing a script tag becomes <script>alert('xss')</script>, which the browser renders as literal text rather than executable code.
HTML attribute context — when inserting data into an HTML attribute (for example, inside an input element's value attribute), encode the five critical characters plus any characters that could break out of the attribute context. Always quote your attributes — unquoted attributes can be broken out of with a space character, which is much harder to defend against.
JavaScript context — when inserting data into a JavaScript string (for example, inside a var x = '...' assignment), HTML entity encoding is NOT sufficient. You need JavaScript string encoding (escaping quotes, backslashes, and control characters). Better yet, avoid inserting untrusted data into inline JavaScript entirely — use data attributes on HTML elements and read them from JavaScript.
URL context — when inserting data into a URL (for example, inside an anchor tag's href attribute as a query parameter), use URL encoding (percent-encoding) for the data, then HTML-entity-encode the entire URL for the attribute context. See our article on URL encoding for details on percent-encoding.
CSS context — when inserting data into a CSS property (for example, inside a style attribute), use CSS encoding (backslash-hex sequences). In practice, avoid inserting untrusted data into CSS entirely — use class names instead.
The key insight is that the encoding must match the context. HTML encoding in a JavaScript context doesn't prevent XSS. URL encoding in an HTML body context doesn't prevent XSS. Each context has its own syntax and its own escape sequences.
Content Security Policy: Defense in Depth
Output encoding is the primary defense, but Content Security Policy (CSP) provides a critical second layer. A CSP is an HTTP header that tells the browser which sources of content (scripts, styles, images, etc.) are allowed on the page. A strict CSP that disallows inline scripts (using a script-src 'self' directive) means that even if an attacker manages to inject a script tag through an encoding failure, the browser will refuse to execute it.
A well-configured CSP includes directives like default-src 'self' (only allow resources from the same origin), script-src 'self' (only allow scripts from the same origin, no inline scripts), and style-src 'self' 'unsafe-inline' (allow styles from same origin plus inline styles, which are lower-risk than inline scripts). The 'unsafe-inline' directive for scripts should be avoided — if you need inline scripts, use nonce-based CSP where each script tag includes a randomly generated nonce value that matches the CSP header.
CSP doesn't replace output encoding — it's defense in depth. A site with perfect output encoding doesn't need CSP to prevent XSS, and a site with a strict CSP can still have XSS issues in non-script contexts (like HTML injection that modifies page content without executing scripts). Both layers together provide robust protection.
Beyond the Five: When to Encode More
While the five critical characters cover most XSS scenarios, there are contexts where additional encoding is needed.
Non-breaking spaces and other Unicode whitespace can cause display issues if not encoded. The non-breaking space (U+00A0) is commonly encoded as in HTML.
Non-ASCII characters (accented letters, CJK characters, emoji) should be safe in a UTF-8 document with the proper meta charset="UTF-8" declaration. However, if you're generating HTML in a non-UTF-8 environment, encoding non-ASCII characters as numeric entities (like é for the accented e) ensures they display correctly regardless of the document's character encoding.
Characters with special meaning in specific contexts — backticks in JavaScript template literals, parentheses in CSS url() values, semicolons in CSS property values — need context-specific encoding that goes beyond the five HTML characters.
For a general-purpose "make this safe for HTML" operation, encoding the five critical characters is sufficient for HTML body and attribute contexts. Our HTML encoder handles this. For JavaScript, URL, and CSS contexts, use the context-specific encoding functions provided by your framework or a library like OWASP's Java Encoder, Microsoft's AntiXSS library, or DOMPurify for client-side HTML sanitization.
HTML Entities for Typography and Symbols
Beyond security, HTML entities are used for typographic characters that aren't easily typed on a standard keyboard. Common examples include: — for the em dash, – for the en dash, ‘ and ’ for curly single quotes, “ and ” for curly double quotes, … for the ellipsis, © for the copyright symbol, ™ for the trademark symbol, and ° for the degree symbol.
These entities are technically unnecessary in a UTF-8 HTML document — you can type the actual characters directly, and modern browsers will render them correctly. But entities are useful when your text editor doesn't support the character, when you want to be explicit about which character you're using (is that an en dash or a hyphen?), or when you're generating HTML programmatically and want to avoid character encoding issues.
The HTML specification defines over 2,200 named entities. The full list is in the HTML Living Standard. For quick encoding and decoding of any text, use our HTML encoder and HTML decoder.
HTML Encoding in Practice
Most modern web frameworks handle output encoding automatically through their templating systems. React escapes all values embedded in JSX by default — you have to explicitly use dangerouslySetInnerHTML to insert raw HTML. Angular escapes interpolated values in templates by default. Django's template engine auto-escapes variables. Jinja2 (used by Flask) auto-escapes in HTML contexts. ASP.NET Razor auto-escapes expressions rendered with the at-sign syntax.
The danger comes from explicitly bypassing these protections — using dangerouslySetInnerHTML in React, innerHTML in vanilla JavaScript, the safe filter in Django/Jinja2, or Html.Raw() in Razor. Every use of these should be accompanied by either manual encoding of the specific characters that matter, or sanitization with a library like DOMPurify that strips dangerous HTML while preserving safe formatting.
If you're working outside a framework — generating HTML manually in a script, constructing email templates, or building static HTML files — you're responsible for encoding untrusted data yourself. Use our HTML encoder for quick manual encoding, and integrate a proper encoding library into any production code that generates HTML from user input.
The Bottom Line
HTML entity encoding is both a display tool and a security mechanism. The five critical characters (the ampersand, less-than sign, greater-than sign, double quote, and single quote) must be encoded whenever untrusted data is inserted into HTML to prevent XSS attacks. The encoding must be context-appropriate — HTML encoding for HTML contexts, URL encoding for URL contexts, JavaScript encoding for JavaScript contexts. Modern frameworks handle this automatically in most cases, but bypassing auto-escaping (which is sometimes necessary) requires careful manual encoding or sanitization. Defense in depth with Content Security Policy provides a safety net for encoding failures.
References
OWASP — Cross-Site Scripting Prevention Cheat Sheet — The authoritative guide to preventing XSS through output encoding.
HTML Living Standard — Named Character References — The complete list of all 2,200+ HTML named entities.
W3Schools — HTML Entities — Quick reference for common HTML entities.
Wikipedia — List of XML and HTML Character Entity References — Comprehensive reference table with code points and entity names.
MDN — Cross-Site Scripting (XSS) — Mozilla's overview of XSS types and prevention.