2026-08-28 · 6 min read · Rahul Chitturi
- html
- security
- debugging
Text that renders as & or ' has usually crossed more than one encoding boundary. One layer stores an already escaped value and another template correctly escapes the ampersand again, producing visible entity text.
The tempting fix is to disable escaping globally. That replaces a display bug with a cross-site scripting risk because HTML text, attributes, URLs, CSS, and JavaScript strings require different handling.
Trace the value in its unambiguous forms
Start with a harmless fixture containing ampersands, angle brackets, quotes, and Unicode. Record the stored value, serialized API value, template input, generated markup, and final DOM text separately.
- Store canonical text rather than pre-escaped display markup
- Let the template escape once for the current output context
- Use textContent for plain DOM text instead of innerHTML
- Validate URL schemes before placing values in href or src
Keep decoding away from trust decisions
Entity decoding converts representation; it does not sanitize markup. If an application intentionally accepts HTML, use a proven sanitizer with an explicit policy and keep that path separate from ordinary text fields.
Compare the DOM property the user sees with the HTML source. Browsers decode entities while parsing, so these views are expected to differ even when the result is correct.
A Flashman workflow
Use the HTML entities tool with synthetic text, the URL tool for attribute components, the diff tool to locate the extra encoding pass, and the JSON formatter to inspect API escaping.
Add tests for text nodes, quoted attributes, URLs, and any intentionally sanitized rich-text field. Each test should assert the final DOM value as well as safe markup behavior.