The five that matter
Only a handful of characters actually need escaping in HTML: &, <, >, and inside attribute values " and '. Everything else is a display convenience.
The ampersand has to be first. Escape < before & and you turn < into < and then into &lt;, which renders as literal < on the page. That ordering mistake is behind a good share of double-escaped text.
Why you keep seeing &amp;
Because something escaped text that was already escaped. Each pass turns & into &, so &amp; means three passes. Decoding here undoes them one layer at a time, which is useful for diagnosing how many there were.
The fix is upstream: escape once, at the point where text is put into markup, and never on the way into storage.
Escaping is context-sensitive
HTML escaping makes text safe in HTML. It does not make it safe inside a <script> block, inside a URL, or inside a CSS rule — those have their own rules, and applying the wrong one leaves a hole that looks closed.
Frequently asked questions
Why does my page show &amp; instead of &?
The text was escaped twice. Each pass turns & into &amp;. Decode it once here to confirm, then fix whichever step is escaping already-escaped text.
Which characters actually need escaping?
In body text, & < and >. In attribute values, also " and '. The rest are optional and mostly a legacy of older character-set problems.
Is escaping enough to prevent XSS?
In HTML body context, yes. Inside a script block, a URL or a style rule it is not — each needs its own escaping, and HTML escaping there gives false confidence.
What is the difference between &#39; and &apos;?
Both are an apostrophe. The numeric form works everywhere including old HTML 4 parsers; &apos; was only added in XHTML, so the numeric one is safer.
Something wrong with this tool, or an idea for it? Tell us