CVE-2016-1000237
Description
sanitize-html before 1.4.3 has XSS.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Sanitize-html before 1.4.3 fails to apply sanitization recursively, allowing attackers to bypass filters and inject XSS via nested HTML tags.
Vulnerability
The sanitize-html library before version 1.4.3 contains a cross-site scripting (XSS) vulnerability because it does not apply sanitization recursively [1]. The library processes input HTML in a single pass, so an attacker can craft nested tags that survive the first sanitization pass and become valid malicious HTML after the filter removes outer layers [3][4].
Exploitation
An attacker can exploit this by submitting input such as <img src="x">. After one pass, the outer angle brackets are stripped, leaving `` which is a valid XSS vector. No special privileges are required; the attack works on any application that uses the library to sanitize user-supplied HTML without additional validation.
Impact
Successful exploitation allows an attacker to inject arbitrary JavaScript into the application's context, leading to XSS attacks such as session hijacking, data theft, or defacement.
Mitigation
The vulnerability is fixed in version 1.4.3. The fix introduces recursive sanitization: the library repeatedly sanitizes the output until no further changes occur, preventing nested bypass attempts [2]. Users should upgrade to 1.4.3 or later.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
sanitize-htmlnpm | < 1.4.3 | 1.4.3 |
Affected products
2- sanitize-html/sanitize-htmldescription
Patches
1762fbc7bba38recursive invocation to protect against https://github.com/fb55/htmlparser2/issues/105
4 files changed · +40 −5
index.js+19 −3 modified@@ -4,7 +4,11 @@ var he = require('he'); module.exports = sanitizeHtml; -function sanitizeHtml(html, options) { +// Ignore the _recursing flag; it's there for recursive +// invocation as a guard against this exploit: +// https://github.com/fb55/htmlparser2/issues/105 + +function sanitizeHtml(html, options, _recursing) { var result = ''; function Frame(tag, attribs) { @@ -87,8 +91,8 @@ function sanitizeHtml(html, options) { var skipText = false; var parser = new htmlparser.Parser({ onopentag: function(name, attribs) { - var frame = new Frame(name, attribs); - stack.push(frame); + var frame = new Frame(name, attribs); + stack.push(frame); var skip = false; if (_.has(transformTagsMap, name)) { @@ -198,6 +202,18 @@ function sanitizeHtml(html, options) { }); parser.write(html); parser.end(); + + // Invoke recursively until we stop finding + // clever little nesting exploits + if (!_recursing) { + while (true) { + var newResult = sanitizeHtml(result, options, true); + if (newResult === result) { + return result; + } + result = newResult; + } + } return result; function escapeHtml(s) {
package.json+1 −1 modified@@ -22,7 +22,7 @@ "license": "MIT", "dependencies": { "he": "~0.4.1", - "htmlparser2": "~3.3.0", + "htmlparser2": "3.7.x", "lodash": "2.4.x" } }
README.md+4 −0 modified@@ -180,6 +180,10 @@ sanitizeHtml( ## Changelog +1.4.3: invokes itself recursively until the markup stops changing to guard against [this issue](https://github.com/fb55/htmlparser2/issues/105). Bump to htmlparser2 version 3.7.x. + +1.4.1, 1.4.2: more tests. + 1.4.0: ability to allow all attributes or tags through by setting `allowedAttributes` and/or `allowedTags` to false. Thanks to Anand Thakker. 1.3.0: `attribs` now available on frames passed to exclusive filter.
test/test.js+16 −1 modified@@ -281,6 +281,21 @@ describe('sanitizeHtml', function() { } ), '' - ) + ); + }); + it('should not be faked out by double <', function() { + assert.equal( + sanitizeHtml('<<img src="javascript:evil"/>img src="javascript:evil"/>' + ), + '' + ); + // I don't love what I get back here obviously, but + // it is not an attack vector, although it might be parsed + // by some browsers as containing an unbalanced close tag. + assert.equal( + sanitizeHtml('<<a href="javascript:evil"/>a href="javascript:evil"/>' + ), + '<<a>a href="javascript:evil"/></a>' + ); }); });
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-3j7m-hmh3-9jmpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-1000237ghsaADVISORY
- github.com/apostrophecms/sanitize-html/commit/762fbc7bba389f3f789cc291c1eb2b64f60f2cafghsaWEB
- github.com/apostrophecms/sanitize-html/issues/29ghsaWEB
- github.com/punkave/sanitize-html/issues/29ghsaWEB
- nodesecurity.io/advisories/135mitrex_refsource_MISC
- raw.githubusercontent.com/distributedweaknessfiling/cvelist/master/2016/1000xxx/CVE-2016-1000237.jsonghsax_refsource_MISCWEB
- www.npmjs.com/advisories/135ghsaWEB
News mentions
0No linked articles in our index yet.