HTML String Escaper

Escaping the five HTML special characters prevents user input from being read as markup. It is a genuine and necessary defence, and it is also the source of a persistent false sense of security, because escaping for one context does nothing for the four other contexts input can land in.

How to use it

  1. Paste the text you need to escape.
  2. Ampersands, angle brackets, and quotes are replaced with their entity equivalents.
  3. Copy the escaped output. Nothing is transmitted.

The five characters and why each one matters

Escaping replaces characters that have structural meaning in HTML with entity references that render as the literal character.

The set, and the attack each one blocks:

Escaping is context-dependent, and this is where XSS comes from

HTML escaping is correct for text placed between tags. It is insufficient, and sometimes irrelevant, everywhere else.

Inside an unquoted attribute value, escaping the five characters is not enough, because a space or a tab terminates the attribute just as effectively as a quote does. The fix is to always quote attribute values, not to escape harder.

Inside a script block, HTML escaping does nothing useful. The content is parsed as JavaScript, so a value interpolated there needs JavaScript string escaping, and even then a closing script tag sequence inside a string will terminate the block. Interpolating user data into inline script is a pattern to avoid entirely.

Inside a URL context, such as an href or src attribute, escaping the five characters does not prevent a javascript: URL. That requires validating the scheme.

Inside a style block or attribute, CSS has its own escaping rules and its own historical injection vectors.

What to do instead of escaping by hand

Modern template engines escape by default and know which context they are in. React, Vue, Angular, Jinja, and Rails all do this, and the practical advice is to stop fighting them: the dangerous constructs are the escape hatches, named things like dangerouslySetInnerHTML and safe, and each one deserves scrutiny in review.

When you genuinely need to render user-supplied HTML, such as output from a rich text editor, escaping is the wrong tool because it would show the markup as text. Sanitisation is what you want, using a library such as DOMPurify that parses the HTML and removes dangerous elements and attributes while keeping the safe ones. Do not attempt this with regular expressions; every hand-rolled HTML sanitiser has been bypassed.

A Content Security Policy is the layer underneath, limiting the damage when something does get through. It is a mitigation rather than a fix, and it is worth having.

Legitimate uses for manual escaping

Displaying code samples on a page, where you want readers to see the tags rather than have the browser render them. Putting a value into a static HTML file by hand. Preparing content for a system whose templating you do not control. Debugging, when you need to see exactly what a string contains.

What it is not for is bolting safety onto a rendering path that should have been escaping automatically all along.

At a glance

Escaped characters& < > " and single quote
Single quote form&#39; numeric reference
ContextHTML text and quoted attribute values
TransmittedNothing

Frequently asked questions

Does escaping these five characters prevent XSS?

In HTML text and quoted attributes, largely yes. In unquoted attributes, script blocks, URL attributes, and CSS, no. Each context needs its own encoding, which is why context-aware templating is the real defence.

Why is the single quote escaped as a number?

The named entity &apos; is defined in XML and XHTML but not in HTML 4, so older parsers render it literally. The numeric reference &#39; works everywhere.

Should I escape user input before storing it?

Generally no. Store the raw value and escape at render time, when you know the output context. Escaping on input produces double-encoded text as soon as the data is rendered somewhere other than HTML.

How do I safely display user-submitted rich text?

Sanitise rather than escape, using a parser-based library such as DOMPurify. Escaping would display the markup as text rather than rendering it, and regex-based filtering has been bypassed every time it has been tried.

Read more

Formatting and encoding — Pretty-printing catches bugs, Base64 costs 33 percent, and escaping applied in the wrong context prevents nothing.

Related tools