NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #3077 most downloaded on npm
Clean up user-submitted HTML, preserving allowlisted elements and allowlisted attributes on a per-element basis
Last release 4 days ago
30 Sep 2026
Ships unpredictably
gaps range from 3 weeks to 9 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
13 years old
127 releases · first in 2013
Fix failing tests, add CircleCI config
Fix failing tests, add CircleCI config
reduced size of npm package via the files key; we only need to publish what's in dist. Thanks to Steven. There should be zero impact on behavior, mino
reduced size of npm package via the files key; we only need to publish what's in dist. Thanks to Steven. There should be zero impact on behavior, minor version bump is precautionary.
One column per quarter.
reverted to postcss due to a reported issue with `css-tree` that might or might not have XSS implications.
reverted to postcss due to a reported issue with css-tree that might or might not have XSS implications.
Switched out the heavy postcss dependency for the lightweight css-tree module. No API changes. Thanks to Justin Braithwaite.
postcss dependency for the lightweight css-tree module. No API changes. Thanks to Justin Braithwaite." characters are now entity-escaped only when they appear in attribute values, reducing the verbosity of the resulting markup.
" characters are now entity-escaped only when they appear in attribute values, reducing the verbosity of the resulting markup.
Fixed a regression introduced in version 1.18.5 in the handling of markup that looks similar to a valid entity, but isn't. The bogus entity was passed through intact, i.e. &0; did not become &0; as it should have. This fix has been made for the default parser settings only. There is no fix yet for those who wish to enable decodeEntities: false. That will require improving the alternative encoder in the escapeHtml function to only pass 100% valid entities.
For those using the default parser settings this bug is fixed. Read on if you are using alternative parser settings.
When decodeEntities: true is in effect (the default), this is not a problem because we only have to encode & < > " and we always encode those things.
There is currently a commented-out test which verifies one example of the problem when decodeEntities is false. However a correct implementation would need to not only pass that simple example but correctly escape all invalid entities, and not escape those that are valid.
New allowIframeRelativeUrls option. It defaults to true unless allowedIframeHostnames is present, in which case it defaults to false, for backwards co
allowIframeRelativeUrls option. It defaults to true unless allowedIframeHostnames is present, in which case it defaults to false, for backwards compatibility with existing behavior in both cases; however you can now set the option explicitly to allow both certain hostnames and relative URLs. Thanks to Rick Martin.Stop double encoding ampersands on HTML entities. Thanks to Will Gibson.
Removed incorrect browser key, restoring frontend build. Thanks to Felix Becker.
browser key, restoring frontend build. Thanks to Felix Becker.iframe is an allowed tag by default, to better facilitate typical use cases and the use of the allowedIframeHostnames option.
iframe is an allowed tag by default, to better facilitate typical use cases and the use of the allowedIframeHostnames option.Fixed another case issue — and instituted Travis CI testing so this doesn't happen again. Sorry for the hassle.
A file was required with incorrect case, breaking the library on case sensitive filesystems such as Linux. Fixed.
The new allowedSchemesAppliedToAttributes option. This determines which attributes are validated as URLs, replacing the old hardcoded list of src and
allowedSchemesAppliedToAttributes option. This determines which attributes are validated as URLs, replacing the old hardcoded list of src and href only. The default list now includes cite. Thanks to ml-dublin for this contribution.allowedAttributes, rather than listing an attribute name, simply list an object with an attribute name property and an allowed values array property. You can also add multiple: true to allow multiple space-separated allowed values in the attribute, otherwise the attribute must match one and only one of the allowed values. Thanks again to ml-dublin for this contribution.The new allowedIframeHostnames option. If present, this must be an array, and only iframe src URLs hostnames (complete hostnames; domain name matches
The new allowedIframeHostnames option. If present, this must be an array, and only iframe src URLs hostnames (complete hostnames; domain name matches are not enough) that appear on this list are allowed. You must also configure hostname as an allowed attribute for iframe. Thanks to Ryan Verys for this contribution.
Don't throw away the browserified versions before publishing them. prepare is not a good place to make clean, it runs after prepublish.
Don't throw away the browserified versions before publishing them. prepare is not a good place to make clean, it runs after prepublish.
sanitize-html is now compiled with babel. An npm prepublish script takes care of this at npm publish time, so the latest code should always be compile
sanitize-html is now compiled with babel. An npm prepublish script takes care of this at npm publish time, so the latest code should always be compiled to operate all the way back to ES5 browsers and earlier versions of Node. Thanks to Ayushya Jaiswal.
Please note that running sanitize-html in the browser is usually a security hole. Are you trusting the browser? Anyone could bypass that using the network panel. Sanitization is almost always best done on servers and that is the primary use case for this module.
changelog formatting only.
changelog formatting only.
support for sanitizing inline CSS styles, by specifying the allowed attributes and a regular expression for each. Thanks to Cameron Will and Michael L
support for sanitizing inline CSS styles, by specifying the allowed attributes and a regular expression for each. Thanks to Cameron Will and Michael Loschiavo.
if configured as an allowed attribute (not the default), check for naughty URLs in srcset attributes. Thanks to Mike Samuel for the nudge to do this a
if configured as an allowed attribute (not the default), check for naughty URLs in srcset attributes. Thanks to Mike Samuel for the nudge to do this and to Sindre Sorhus for the srcset module.
inadvertent removal of lodash regexp quote dependency in 1.14.2 has been corrected.
inadvertent removal of lodash regexp quote dependency in 1.14.2 has been corrected.
protocol-relative URL detection must spot URLs starting with \\ rather than // due to ages-old tolerance features of web browsers, intended for sleepy
protocol-relative URL detection must spot URLs starting with \\ rather than // due to ages-old tolerance features of web browsers, intended for sleepy Windows developers. Thanks to Martin Bajanik.
documented allowProtocolRelative option. No code changes from 1.14.0, released a few moments ago.
documented allowProtocolRelative option. No code changes from 1.14.0, released a few moments ago.
the new allowProtocolRelative option, which is set to true by default, allows you to decline to accept URLs that start with // and thus point to a dif
the new allowProtocolRelative option, which is set to true by default, allows you to decline to accept URLs that start with // and thus point to a different host using the current protocol. If you do not want to permit this, set this option to false. This is fully backwards compatible because the default behavior is to allow them. Thanks to Luke Bernard.
transformTags can now add text to an element that initially had none. Thanks to Dushyant Singh.
transformTags can now add text to an element that initially had none. Thanks to Dushyant Singh.
option to build for browser-side use. Thanks to Michael Blum.
option to build for browser-side use. Thanks to Michael Blum.
fixed crash when __proto__ is a tag name. Now using a safe check for the existence of properties in all cases. Thanks to Andrew Krasichkov.
fixed crash when __proto__ is a tag name. Now using a safe check for the existence of properties in all cases. Thanks to Andrew Krasichkov.
Fixed XSS attack vector via textarea tags (when explicitly allowed). Decided that script (obviously) and style (due to its own XSS vectors) cannot realistically be afforded any XSS protection if allowed, unless we add a full CSS parser. Thanks again to Andrew Krasichkov.
bumped htmlparser2 version to address crashing bug in older version. Thanks to e-jigsaw.
bumped htmlparser2 version to address crashing bug in older version. Thanks to e-jigsaw.
fixed README typo that interfered with readability due to markdown issues. No code changes. Thanks to Mikael Korpela. Also improved code block highlig
fixed README typo that interfered with readability due to markdown issues. No code changes. Thanks to Mikael Korpela. Also improved code block highlighting in README. Thanks to Alex Siman.
fixed a regression introduced in 1.11.0 which caused the closing tag of the parent of a textarea tag to be lost. Thanks to Stefano Sala, who contribut
fixed a regression introduced in 1.11.0 which caused the closing tag of the parent of a textarea tag to be lost. Thanks to Stefano Sala, who contributed the missing test.
added the nonTextTags option, with tests.
added the nonTextTags option, with tests.
documentation cleanup. No code changes. Thanks to Rex Schrader.
documentation cleanup. No code changes. Thanks to Rex Schrader.
allowedAttributes now allows you to allow attributes for all tags by specifying * as the tag name. Thanks to Zdravko Georgiev.
allowedAttributes now allows you to allow attributes for all tags by specifying * as the tag name. Thanks to Zdravko Georgiev.
parser option allows options to be passed directly to htmlparser. Thanks to Danny Scott.
parser option allows options to be passed directly to htmlparser. Thanks to Danny Scott.
transformTags now accepts the * wildcard to transform all tags. Thanks to Jamy Timmermans.
transformTags now accepts the * wildcard to transform all tags. Thanks to Jamy Timmermans.
Text that has been modified by transformTags is then passed through textFilter. Thanks to Pavlo Yurichuk.
Content inside textarea is discarded if textarea is not allowed. I don't know why it took me this long to see that this is just common sense. Thanks to David Frank.
removed array-includes dependency in favor of indexOf, which is a little more verbose but slightly faster and doesn't require a shim. Thanks again to
removed array-includes dependency in favor of indexOf, which is a little more verbose but slightly faster and doesn't require a shim. Thanks again to Joseph Dykstra.
removed lodash dependency, adding lighter dependencies and polyfills in its place. Thanks to Joseph Dykstra.
removed lodash dependency, adding lighter dependencies and polyfills in its place. Thanks to Joseph Dykstra.
introduced allowedSchemesByTag option. Thanks to Cameron Will.
introduced allowedSchemesByTag option. Thanks to Cameron Will.
the string 'undefined' (as opposed to undefined) is perfectly valid text and shouldn't be expressly converted to the empty string.
the string 'undefined' (as opposed to undefined) is perfectly valid text and shouldn't be expressly converted to the empty string.
added textFilter option. Thanks to Csaba Palfi.
added textFilter option. Thanks to Csaba Palfi.
do not escape special characters inside a script or style element, if they are allowed. This is consistent with the way browsers parse them; nothing c
do not escape special characters inside a script or style element, if they are allowed. This is consistent with the way browsers parse them; nothing closes them except the appropriate closing tag for the entire element. Of course, this only comes into play if you actually choose to allow those tags. Thanks to aletorrado.
guard checks for allowed attributes correctly to avoid an undefined property error. Thanks to Zeke.
guard checks for allowed attributes correctly to avoid an undefined property error. Thanks to Zeke.
@apostrophecms/sitemap@1.5.1
@apostrophecms/sitemap@1.5.1
updated to htmlparser2 1.8.x. Started using the decodeEntities option, which allows us to pass our filter evasion tests without the need to recursively invoke the filter.
support for * wildcards in allowedAttributes. With tests. Thanks to Calvin Montgomery.
support for * wildcards in allowedAttributes. With tests. Thanks to Calvin Montgomery.
invokes itself recursively until the markup stops changing to guard against this issue. Bump to htmlparser2 version 3.7.x.
invokes itself recursively until the markup stops changing to guard against this issue. Bump to htmlparser2 version 3.7.x.
Nothing published for this version
more tests.
more tests.
attribs now available on frames passed to exclusive filter.
attribs now available on frames passed to exclusive filter.
fixed another possible XSS attack vector; no definitive exploit was found but it looks possible. See this issue. Thanks to Jim O'Brien.
fixed another possible XSS attack vector; no definitive exploit was found but it looks possible. See this issue. Thanks to Jim O'Brien.
reject javascript: URLs when disguised with an internal comment. This is probably not respected by browsers anyway except when inside an XML data isla
reject javascript: URLs when disguised with an internal comment. This is probably not respected by browsers anyway except when inside an XML data island element, which you almost certainly are not allowing in your allowedTags, but we aim to be thorough. Thanks to Jim O'Brien.
fixed crashing bug when presented with bad markup. The bug was in the exclusiveFilter mechanism. Unit test added. Thanks to Ilya Kantor for catching i
fixed crashing bug when presented with bad markup. The bug was in the exclusiveFilter mechanism. Unit test added. Thanks to Ilya Kantor for catching it.
@apostrophecms/vite@1.2.0
@apostrophecms/vite@1.2.0
The allowedClasses option now allows you to permit CSS classes in a fine-grained way.
Text passed to your exclusiveFilter function now includes the text of child elements, making it more useful for identifying elements that truly lack any inner text.
Nothing published for this version
use he for entity decoding, because it is more actively maintained.
use he for entity decoding, because it is more actively maintained.
just a packaging thing.
just a packaging thing.
custom exclusion filter.
custom exclusion filter.
moved to lodash. 1.1.2 pointed to the wrong version of lodash.
moved to lodash. 1.1.2 pointed to the wrong version of lodash.
Nothing published for this version
Nothing published for this version
the transformTags option was added. Thanks to kl3ryk.
the transformTags option was added. Thanks to kl3ryk.
fixed several more javascript URL attack vectors after studying the XSS filter evasion cheat sheet to better understand my enemy. Whitespace character
fixed several more javascript URL attack vectors after studying the XSS filter evasion cheat sheet to better understand my enemy. Whitespace characters (codes from 0 to 32), which browsers ignore in URLs in certain cases allowing the "javascript" scheme to be snuck in, are now stripped out when checking for naughty URLs. Thanks again to pinpickle.
fixed a javascript URL attack vector. naughtyHref must entity-decode URLs and also check for mixed-case scheme names. Thanks to pinpickle.
fixed a javascript URL attack vector. naughtyHref must entity-decode URLs and also check for mixed-case scheme names. Thanks to pinpickle.
Your coding agent can read these notes before it upgrades. Set up the MCP server →