HTML sanitization for user-supplied rich text.
Backed by MDEx.safe_html/2 — an ammonia-based parsed allowlist. It
builds a real DOM, keeps only known-good tags and attributes, validates
URL schemes per attribute, and re-serializes. It does not pattern-match
on markup, which is why it holds up where the previous regex
implementation did not (see sanitize_html/1).
What survives
Ordinary rich text: block elements (p, div, hr, h1-h6, blockquote, pre,
code), inline elements (span, strong, em, u, s, a, sub, sup), lists,
tables, and img. Relative, absolute, anchor, mailto: and tel: URLs
are preserved, as are class on any tag and target on links.
What is removed
Script and style elements, event-handler attributes, dangerous URL
schemes (javascript:, data:, …) including entity-encoded
spellings such as javascript:, and embedding elements
(iframe, object, embed, svg, math).
Attributes outside the allowlist go too, and the allowlist is narrower
than the one this module shipped before the rewrite. Most notably id
is dropped from every tag, so href="#..." can only reach an anchor
the application itself rendered, not one stored in the content. Also
gone: rel (re-stamped as noopener noreferrer on every link),
<input> — so Markdown task-list checkboxes vanish — and <tfoot>.
sanitize_html/1 carries the reasoning and the knobs.
Output is normalised
Because the result is re-serialized from a parse tree, it is valid HTML
rather than a lightly-edited copy of the input: attribute values come
back quoted, void elements lose a self-closing slash (<br/> →
<br>), <table> gains an implicit <tbody>, and links gain
rel="noopener noreferrer". Compare rendered meaning, not exact
strings, when asserting on sanitized output.
Usage
PhoenixKit.Utils.HtmlSanitizer.sanitize("<p>Hello</p><script>alert('xss')</script>")
#=> "<p>Hello</p>"
PhoenixKit.Utils.HtmlSanitizer.sanitize(~s|<a href="javascript:alert(1)">Click</a>|)
#=> "<a rel=\"noopener noreferrer\">Click</a>"
Summary
Functions
Sanitizes HTML content by removing dangerous elements and attributes.
Sanitizes all rich_text fields in an entity data map.
Functions
Sanitizes HTML content by removing dangerous elements and attributes.
Returns sanitized HTML string that is safe to render.
Parameters
html- The HTML string to sanitize
Examples
iex> PhoenixKit.Utils.HtmlSanitizer.sanitize("<p onclick="alert('xss')">Hello</p>")
"<p>Hello</p>"
Sanitizes all rich_text fields in an entity data map.
Takes entity field definitions and data, returns data with all rich_text fields sanitized.
Parameters
fields_definition- List of field definition mapsdata- Map of field key => value
Examples
iex> fields = [%{"type" => "rich_text", "key" => "content"}]
iex> data = %{"content" => "<script>alert('xss')</script><p>Hello</p>"}
iex> PhoenixKit.Utils.HtmlSanitizer.sanitize_rich_text_fields(fields, data)
%{"content" => "<p>Hello</p>"}