Skip to content

fix(deps): update dependency sanitize-html to v2.17.5 [security] - #21

Open
renovate[bot] wants to merge 1 commit into
developfrom
renovate/npm-sanitize-html-vulnerability
Open

fix(deps): update dependency sanitize-html to v2.17.5 [security]#21
renovate[bot] wants to merge 1 commit into
developfrom
renovate/npm-sanitize-html-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Mar 2, 2024

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
sanitize-html (source) 2.7.12.17.5 age confidence

sanitize-html Information Exposure vulnerability

CVE-2024-21501 / GHSA-rm97-x556-q36h

More information

Details

Versions of the package sanitize-html before 2.12.1 are vulnerable to Information Exposure when used on the backend and with the style attribute allowed, allowing enumeration of files in the system (including project dependencies). An attacker could exploit this vulnerability to gather details about the file system structure and dependencies of the targeted server.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


sanitize-html has incomplete URI scheme validation in that allows javascript: URIs through action, formaction, data, poster, and background attributes

CVE-2026-53606 / GHSA-vccv-cmxp-4j9h

More information

Details

Summary

sanitize-html uses allowedSchemesAppliedToAttributes (default: ['href', 'src', 'cite']) to gate the naughtyHref() function that blocks dangerous URI schemes like javascript: and vbscript:. The HTML specification defines 10+ attributes that accept URIs (action, formaction, data, poster, background, ping, xlink:href, dynsrc, lowsrc), but none of these are included in the default gate list. When a developer allows any of these attributes in their configuration, javascript: URIs pass through completely unmodified, enabling XSS.

The library has zero awareness of these URI-bearing attributes — none appear anywhere in the 854-line source file (verified by grep). No warning mechanism exists, and the README provides no security guidance about expanding allowedSchemesAppliedToAttributes when allowing form or media attributes.

Severity

Exploitation requires non-default configuration: the developer must explicitly allow a non-default tag (e.g., form) AND a non-default attribute (e.g., action). Default configuration is NOT vulnerable. However, this is a common configuration pattern for CMS platforms, form builders, and rich content editors.

Affected Versions

All versions of sanitize-html from v1.18.0 (which introduced allowedSchemesAppliedToAttributes) through at least v2.17.2. The default list has been ['href', 'src', 'cite'] since introduction and has never been expanded.

Root Cause

File: index.js:329 (sanitize-html 2.10.0, confirmed same in 2.17.x)

// Line 329 — The gate that controls scheme validation
if (options.allowedSchemesAppliedToAttributes.indexOf(a) >= 0) {
    if (naughtyHref(name, value)) {
        delete frame.attribs[a];
        return;
    }
}

Default list at line 829:

allowedSchemesAppliedToAttributes: ['href', 'src', 'cite'],

The naughtyHref() function (lines 627-667) correctly blocks javascript:, vbscript:, and other dangerous schemes. However, it has exactly 2 call sites in the entire codebase (lines 330 and 395), both inside the indexOf gate. There is no ungated path.

When attribute name is action, formaction, data, poster, background, etc.:

  • indexOf('action') returns -1
  • The if block is skipped entirely
  • naughtyHref() is never called
  • javascript:alert(1) passes through unmodified

The escapeHtml() function at line 464 provides no defense — it only encodes & < > " characters, which are not present in javascript:alert(1).

Data Flow:

Attacker input: <form action="javascript:alert(document.cookie)">
1. htmlparser2 parses → tag='form', attribs={action:'javascript:alert(document.cookie)'}
2. index.js:298 → allowedAttributes check: 'action' in developer config → PASS
3. index.js:329 → ['href','src','cite'].indexOf('action') → -1 → SKIP naughtyHref()
4. index.js:464 → escapeHtml('javascript:alert(document.cookie)') → unchanged
5. OUTPUT: <form action="javascript:alert(document.cookie)">
Steps to Reproduce
const sanitize = require('sanitize-html');

// ===== VECTOR 1: form action (100% reliable, all modern browsers) =====
const v1 = sanitize(
    '<form action="javascript:alert(document.cookie)"><button>Submit</button></form>',
    {
        allowedTags: ['form', 'button'],
        allowedAttributes: { form: ['action'] }
    }
);
console.log('V1 (action):', v1);
// OUTPUT: <form action="javascript:alert(document.cookie)"><button>Submit</button></form>
// XSS triggers when user submits the form

// ===== VECTOR 2: button formaction (100% reliable) =====
const v2 = sanitize(
    '<button formaction="javascript:alert(1)">Click</button>',
    {
        allowedTags: ['button'],
        allowedAttributes: { button: ['formaction'] }
    }
);
console.log('V2 (formaction):', v2);
// OUTPUT: <button formaction="javascript:alert(1)">Click</button>

// ===== VECTOR 3: object data =====
const v3 = sanitize(
    '<object data="javascript:alert(1)"></object>',
    {
        allowedTags: ['object'],
        allowedAttributes: { object: ['data'] }
    }
);
console.log('V3 (data):', v3);
// OUTPUT: <object data="javascript:alert(1)"></object>

// ===== CONTROL: href IS scheme-checked (expected behavior) =====
const ctrl = sanitize(
    '<a href="javascript:alert(1)">click</a>',
    {
        allowedTags: ['a'],
        allowedAttributes: { a: ['href'] }
    }
);
console.log('Control (href):', ctrl);
// OUTPUT: <a>click</a>   ← href correctly stripped by naughtyHref()

Observed behavior: javascript: preserved on action/formaction/data but correctly stripped on href.

Expected behavior: javascript: should be stripped on ALL URI-bearing attributes, or at minimum, the library should warn developers when they allow URI-bearing attributes not covered by scheme validation.

Impact

An attacker can achieve XSS in applications that use sanitize-html with non-default configurations allowing URI-bearing attributes:

  • <form action="javascript:..."> — XSS on form submission (all modern browsers)
  • <button formaction="javascript:..."> — per-button XSS override (all modern browsers)
  • <object data="javascript:..."> — object load XSS (Chrome, Firefox)
  • <video poster="javascript:..."> — limited browser support but spec-valid

Common vulnerable configurations:

  • CMS platforms allowing form elements for user-generated content
  • Form builder applications
  • Rich text editors with extended tag allowlists
  • Email template editors allowing media/embed tags

Mitigating factors:

  • Default configuration is NOT vulnerable
  • Requires double opt-in: non-default tag + non-default attribute
  • CSP form-action directive mitigates form-based vectors
  • Developers CAN manually add attributes to allowedSchemesAppliedToAttributes
Remediation

Option 1 (Recommended): Expand the default allowedSchemesAppliedToAttributes list:

// index.js line 829, change from:
allowedSchemesAppliedToAttributes: ['href', 'src', 'cite'],

// to:
allowedSchemesAppliedToAttributes: [
    'href', 'src', 'cite', 'action', 'formaction',
    'data', 'poster', 'background', 'ping',
    'xlink:href', 'dynsrc', 'lowsrc'
],

Option 2: Apply naughtyHref() to ALL attributes by default (invert the gate logic).

Option 3: Add a runtime warning when developers allow URI-bearing attributes not in allowedSchemesAppliedToAttributes (analogous to vulnerableTags warning for script/style at lines 124-129).

Reporter

Kevin Lee (Changseon Lee)
OPCIA Corp. / PeanutAI Inc.
Seoul, South Korea
GitHub: crattack

Severity

  • CVSS Score: 5.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

apostrophecms/apostrophe (sanitize-html)

v2.17.5

Compare Source

v2.17.4

Compare Source

Changes
  • sanitize-html and launder now share a single implementation of naughtyHref, based on that which previously existed in sanitize-html.
Security
  • Security vulnerability: the xmp tag could be used to pass forbidden markup through sanitize-html, even when xmp itself is not explicitly allowed All users of sanitize-html should update immediately. Thanks to Vincenzo Turturro for reporting the vulnerability.

v2.17.3

Compare Source

Security
  • Fix vulnerability introduced in version 2.17.2 that allowed XSS attacks if the developer chose to permit option tags. There was no vulnerability when not explicitly allowing option tags.

v2.17.2

Compare Source

Changes
  • Upgrade htmlparser2 from 8.x to 10.1.0. This improves security by correctly decoding zero-padded numeric character references (e.g., &#&#8203;0000001) that previously bypassed javascript: URL detection. Also fixes double-encoding of entities inside raw text elements like textarea and option.

v2.17.1

Compare Source

Fixes
  • Fix unclosed tags (e.g., <hello) returning empty string in escape and recursiveEscape modes. Fixes #​706.
    Thanks to Byeong Hyeon for the fix.

v2.17.0

Compare Source

  • Add preserveEscapedAttributes, allowing attributes on escaped disallowed tags to be retained. Thanks to Ben Elliot for this new option.

v2.16.0

Compare Source

  • Add onOpenTag and onCloseTag events to enable advanced filtering to hook into the parser. Thanks to Rimvydas Naktinis.

v2.15.0

Compare Source

  • Allow keeping tag content when discarding with exclusive filter by returning "excludeTag". Thanks to rChaoz.

v2.14.0

Compare Source

  • Fix adding text with transformTags in cases where it originally had no text child elements. Thanks to f0x.

v2.13.1

Compare Source

  • Fix to allow regex in allowedClasses wildcard whitelist. Thanks to anak-dev.

v2.13.0

Compare Source

  • Documentation update regarding minimum supported TypeScript version.

  • Added disallowedTagsMode: completelyDiscard option to remove the content also in HTML. Thanks to Gauav Kumar for this addition.

v2.12.1

Compare Source

  • Do not parse sourcemaps in post-css. This fixes a vulnerability in which information about the existence or non-existence of files on a server could be disclosed via properly crafted HTML input when the style attribute is allowed by the configuration. Thanks to the Snyk Security team for the disclosure and to Dylan Armstrong for the fix.

v2.12.0

Compare Source

  • Introduced the allowedEmptyAttributes option, enabling explicit specification of empty string values for select attributes, with the default attribute set to alt. Thanks to Na for the contribution.

  • Clarified the use of SVGs with a new test and changes to documentation. Thanks to Gauav Kumar for the contribution.

  • Do not process source maps when processing style tags with PostCSS.

v2.11.0

Compare Source

  • Fix to allow false in allowedClasses attributes. Thanks to Kevin Jiang for this fix!
  • Upgrade mocha version
  • Apply small linter fixes in tests
  • Add .idea temp files to .gitignore
  • Thanks to Vitalii Shpital for the updates!
  • Show parseStyleAttributes warning in browser only. Thanks to mog422 for this update!
  • Remove empty non-boolean attributes via an exhaustive, configurable list of known non-boolean attributes. Thanks to Dylan Armstrong for this update!

v2.10.0

Compare Source

  • Fix auto-adding escaped closing tags. In other words, do not add implied closing tags to disallowed tags when disallowedTagMode is set to any variant of escape -- just escape the disallowed tags that are present. This fixes issue #​464. Thanks to Daniel Liebner
  • Add tagAllowed() helper function which takes a tag name and checks it against options.allowedTags and returns true if the tag is allowed and false if it is not.

v2.9.0

Compare Source

v2.8.1

Compare Source

  • If the argument is a number, convert it to a string, for backwards compatibility. Thanks to Alexander Schranz.

v2.8.0

Compare Source

  • Upgrades htmlparser2 to new major version ^8.0.0. Thanks to Kedar Chandrayan for this contribution.

v2.7.3

Compare Source

  • If allowedTags is falsy but not exactly false, then do not assume that all tags are allowed. Rather, allow no tags in this case, to be on the safe side. This matches the existing documentation and fixes issue #​176. Thanks to Kedar Chandrayan for the fix.

v2.7.2

Compare Source

  • Closing tags must agree with opening tags. This fixes issue #​549, in which closing tags not associated with any permitted opening tag could be passed through. No known exploit exists, but it's better not to permit this. Thanks to
    Kedar Chandrayan for the report and the fix.

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 2, 2024

Copy link
Copy Markdown

Deploying quark with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6c36626
Status: ✅  Deploy successful!
Preview URL: https://5c4f656f.quark.pages.dev
Branch Preview URL: https://renovate-npm-sanitize-html-v.quark.pages.dev

View logs

@vercel

vercel Bot commented Mar 2, 2024

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
quark ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 10, 2025 2:45pm

@renovate
renovate Bot force-pushed the renovate/npm-sanitize-html-vulnerability branch from 422f8b4 to a3a35b4 Compare August 10, 2025 14:44
@renovate renovate Bot changed the title fix(deps): update dependency sanitize-html to v2.12.1 [security] fix(deps): update dependency sanitize-html to v2.12.1 [security] - autoclosed Mar 27, 2026
@renovate renovate Bot closed this Mar 27, 2026
@renovate
renovate Bot deleted the renovate/npm-sanitize-html-vulnerability branch March 27, 2026 02:08
@renovate renovate Bot changed the title fix(deps): update dependency sanitize-html to v2.12.1 [security] - autoclosed fix(deps): update dependency sanitize-html to v2.12.1 [security] Mar 30, 2026
@renovate renovate Bot reopened this Mar 30, 2026
@renovate
renovate Bot force-pushed the renovate/npm-sanitize-html-vulnerability branch 2 times, most recently from a3a35b4 to 2c6ce1d Compare March 30, 2026 21:28
@renovate renovate Bot changed the title fix(deps): update dependency sanitize-html to v2.12.1 [security] fix(deps): update dependency sanitize-html to v2.12.1 [security] - autoclosed Apr 27, 2026
@renovate renovate Bot closed this Apr 27, 2026
@renovate renovate Bot changed the title fix(deps): update dependency sanitize-html to v2.12.1 [security] - autoclosed fix(deps): update dependency sanitize-html to v2.12.1 [security] Apr 27, 2026
@renovate renovate Bot reopened this Apr 27, 2026
@renovate
renovate Bot force-pushed the renovate/npm-sanitize-html-vulnerability branch 2 times, most recently from 2c6ce1d to 6c36626 Compare April 27, 2026 21:22
@renovate
renovate Bot force-pushed the renovate/npm-sanitize-html-vulnerability branch from 6c36626 to 5f98241 Compare August 1, 2026 01:35
@renovate renovate Bot changed the title fix(deps): update dependency sanitize-html to v2.12.1 [security] fix(deps): update dependency sanitize-html to v2.17.5 [security] Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants