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
- Paste the text you need to escape.
- Ampersands, angle brackets, and quotes are replaced with their entity equivalents.
- 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:
- Ampersand becomes &. This must be escaped first, otherwise escaping the others would produce double-encoded output. It also prevents an attacker smuggling an entity through.
- Less-than becomes <. This is the one that stops a script tag being interpreted as a tag at all, and it is the single most important substitution.
- Greater-than becomes >. Less critical on its own, but it prevents an injected fragment from closing a tag the attacker did not open.
- Double quote becomes ". Essential inside double-quoted attribute values, where an unescaped quote closes the attribute and lets the attacker add another, such as an onerror handler.
- Single quote becomes '. Same reasoning for single-quoted attributes. It is written as a numeric reference because the named form, ', is not defined in HTML 4.
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 | ' numeric reference |
| Context | HTML text and quoted attribute values |
| Transmitted | Nothing |
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 ' is defined in XML and XHTML but not in HTML 4, so older parsers render it literally. The numeric reference ' 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.