VYPR
Moderate severityNVD Advisory· Published Jan 23, 2020· Updated Aug 6, 2024

CVE-2016-1000237

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.

PackageAffected versionsPatched versions
sanitize-htmlnpm
< 1.4.31.4.3

Affected products

2

Patches

1
762fbc7bba38

recursive invocation to protect against https://github.com/fb55/htmlparser2/issues/105

https://github.com/apostrophecms/sanitize-htmlTom BoutellOct 14, 2014via ghsa
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

News mentions

0

No linked articles in our index yet.