Repository navigation
Releases
sanitize-html v1.0.2
sanitize-html 1.0.2
Release date: 2026-08-07
This release fixes two security vulnerabilities identified by the
CL-SEC initiative. Users should
upgrade.
Security Fixes
CL-SEC-2026-0214 — Comment-breakout XSS with preserved comments (MEDIUM)
When a policy is configured with :remove-comments nil (a non-default
option; the built-in default, strict, and email policies remove
comments), comment content was serialized verbatim. Plump ends a comment
only at -->, but browsers also end one at --!> and via the abrupt
<!--> / <!---> forms, and Plump decodes entities in comment text
while emitting it raw. A preserved comment such as
<!-- --!><img src=x onerror=alert(1)> --> therefore round-tripped
unchanged and a browser re-parsed it as comment-end followed by live
markup — executing the injected handler. Entity-encoded terminators
(--!>, -->) reached the same sink.
Fix: Preserved comment text is now neutralized before serialization,
operating on Plump's already-decoded text so entity-encoded terminators
are covered. Runs of hyphens are collapsed so -- — and thus -->,
--!>, and <!-- — cannot appear, and a leading >/- or trailing -
is padded so the abrupt-close and closing-delimiter merge cases cannot
form. The default policies remove comments and were unaffected.
CL-SEC-2026-0215 — Denial of service via deeply nested input (MEDIUM)
sanitize-html documented that it returns an empty string for safety when
parsing fails, but its handler-case caught only error. Deeply nested
HTML overflows the control stack inside Plump's recursive parser, which
signals control-stack-exhausted — a storage-condition, not an error
— so it escaped the guard and propagated to the caller as an unhandled
condition. Roughly 20,000 nested elements (about 98 KB, closing tags not
even required) were sufficient to crash the calling thread.
Fix: The guard now catches (or storage-condition error). Because
handler-case unwinds the deep stack before running the handler,
returning "" is reliable. Interrupts and other non-storage
serious-conditions still propagate.
Acknowledgments
Security issues identified by the CL-SEC (Common Lisp Security
Initiative) automated audit.
sanitize-html v1.0.1
sanitize-html 1.0.1
Release date: 2026-06-22
This release fixes a security vulnerability identified by the
CL-SEC initiative. Users should
upgrade.
Security Fixes
CL-SEC-2026-0211 — Backslash protocol-relative URL bypass (MEDIUM)
The protocol-allowed-p function rejected protocol-relative URLs
beginning with // (the CL-SEC-2026-0132 fix), but not the backslash
equivalents. Per the WHATWG URL Standard, a backslash is treated as a
forward slash in the authority position of http(s) URLs, so
/\evil.com/x, \/evil.com, and \\evil.com all resolve to the
protocol-relative reference //evil.com/x — yet they passed the
relative-URL allowance because the second character was not a literal
/. This allowed an attacker to load resources from an arbitrary
domain via the href, src, cite, poster, background, and
srcset attributes (tracking pixels, IP/data exfiltration via
auto-loaded images, and open-redirect / phishing on links). The
default policy was affected; no special configuration was required.
Fix: The relative-URL check now treats / and \ alike. A URL is
accepted as relative only when it starts with a single separator that is
not immediately followed by another separator, so //, /\, \/, and
\\ are all rejected as protocol-relative.
Acknowledgments
Security issue identified by the CL-SEC (Common Lisp Security
Initiative) automated audit.
sanitize-html v1.0.0
sanitize-html 1.0.0
Release date: 2026-03-31
This release addresses 4 security vulnerabilities identified by the
CLSEC initiative, including 2
critical XSS bypasses. All users should upgrade immediately.
Security Fixes
CLSEC-2026-0129 — Double-encoded entity reversal enables XSS (CRITICAL)
The decode-double-encoded-entities function performed post-serialization
regex rewriting of Plump's entity-encoded output, reversing safe encoding
back into active HTML characters. This anti-pattern created a fragile
security boundary that could be bypassed.
Fix: The function has been removed entirely. Plump's serializer
produces correct output; double-encoding is no longer an issue.
CLSEC-2026-0130 — SVG/MathML namespace enables mXSS (CRITICAL)
The sanitizer had no special handling for SVG or MathML elements. These
were processed by the "remove tag, keep children" path, promoting their
content into the document. SVG <foreignObject> and MathML
<annotation-xml> re-enter HTML parsing context, enabling mutation XSS
(mXSS) where the sanitizer's DOM tree differs from the browser's
re-parsing.
Fix: SVG, MathML, iframe, object, embed, applet, base, meta, link,
template, audio, video, source, track, param, xmp, listing, and
plaintext are now on the full-removal list — their content is discarded,
not promoted.
CLSEC-2026-0131 — CSS comment bypass in expression() check (HIGH)
The css-value-dangerous-p function did not strip CSS comments before
checking for dangerous keywords. IE's CSS parser ignores comments, so
exp/**/ression(alert(1)) was interpreted as expression(alert(1)) by
the browser but bypassed the sanitizer's keyword check.
Fix: CSS comments are now stripped via strip-css-comments before
keyword matching.
CLSEC-2026-0132 — Protocol-relative URL bypass (MEDIUM)
Protocol-relative URLs (//evil.com/track.gif) passed the
protocol-allowed-p check because they start with /, which matched
the relative-URL allowance. This enabled loading resources from
attacker-controlled domains.
Fix: The relative-URL check now rejects URLs starting with //.
Other Changes
- Version bumped to 1.0.0 to reflect production readiness and the
security audit milestone. - Added GitHub Actions release workflow.
Acknowledgments
Security issues identified by the CLSEC (Common Lisp Security
Initiative) automated audit.