Linter Rule: Disallow unescaped HTML entities
Rule: html-no-unescaped-entities
Description
Disallow unescaped special characters in HTML attribute values and text content. Characters like <, >, and & have special meaning in HTML and should be replaced with their corresponding character references when used as literal values.
This rule checks both attribute values and text content for unescaped <, >, and & characters. ERB output tags are ignored, as the escaping responsibility belongs to the Ruby layer. Only the static (literal) portions of mixed attribute values are checked.
Content inside raw text elements (<script> and <style>) is not checked, as character references are not decoded in those contexts per the HTML spec. Content inside escapable raw text elements (<textarea> and <title>) is still checked.
The & detection validates named references against the full HTML spec character reference list, so &, <, ©, etc. are recognized as valid, while ¬avalidname; would be flagged.
Rationale
Unescaped special characters in HTML can cause parsing ambiguities, rendering issues, and security vulnerabilities. Browsers may interpret unescaped < and > as tag boundaries, leading to broken layouts or unintended element creation. Unescaped & characters can be misinterpreted as the start of a character reference, producing unexpected characters in the output.
Using proper character references ensures that the document is parsed correctly and consistently across all browsers.
| Character | Entity | Context |
|---|---|---|
< | < | Attribute values and text content |
> | > | Attribute values and text content |
& | & | Attribute values and text content |
Autofix
This rule provides an unsafe autofix that replaces unescaped characters with their corresponding character references. The autofix is considered unsafe because replacing characters may change the intended behavior in some contexts (e.g., URLs with query parameters).
Examples
✅ Good
<div class="hello"></div><div data-html="<br>"></div><a href="/path?a=1&b=2">Link</a><div data-char="<>"></div><div data-char="<>"></div><div data-html="<div class="test">content</div>"></div><div class="<%= value %>"></div><div data-value="prefix-<%= value %>-suffix"></div><div>Tom & Jerry</div><script>var x = a & b;</script><style>.foo { content: "a & b"; }</style>🚫 Bad
<div data-html="<br>"></div><div data-expr="a > b"></div><a href="/path?a=1&b=2">Link</a><div data-html="<b>bold & italic</b>"></div><div>Tom & Jerry</div><p>Hello this is < content</p><p>a > b</p>