Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessSubmit crafted HTML to sanitizer endpoint
-
ExploitDisallowed iframe raw-text triggers recursive sanitize call
-
ExecutionUnbounded recursion consumes call stack
-
ImpactStack exhaustion disrupts Node.js request/service
Vulnerability Assessment
| Weakness |
CWE
ASVS 5.0
V15 - Secure Coding and Architecture Recursion depth limits
|
| Exploitation Conditions | Exploitation requires that the application feeds attacker-influenced HTML into sanitize-html 2.18.0 while running the default configuration - specifically with <iframe> NOT in allowedTags and disallowedTagsMode set to 'discard' (both are the library defaults), so most unmodified deployments are exposed. The payload must contain a disallowed <iframe> whose raw-text content nests deeply enough to overflow the Node.js call stack. Limiting factors: there must exist an application path that routes untrusted HTML to sanitizeHtml (e.g. a public comment/form or an editor input); deployments that explicitly allow iframes or set disallowedTagsMode to a non-'discard' mode avoid the recursive path; and impact is confined to availability (a failed request or stack-overflow error), with no data exposure. Per CVSS PR:N the flaw is reachable without authentication, though in ApostropheCMS the HTML-submission surface may in practice sit behind editor permissions depending on where sanitize-html is invoked. |
| Impact | This is a genuine but moderate-severity denial-of-service issue, not a critical priority. The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L, base 5.3) correctly signals a remotely reachable, low-complexity, unauthenticated flaw whose only impact is low availability - there is no confidentiality or integrity exposure (C:N/I:N). The root cause (CWE-674 uncontrolled recursion in sanitize-html 2.18.0: a disallowed <iframe> under the default disallowedTagsMode 'discard' re-sanitizes its raw-text content via an unbounded recursive sanitizeHtml call) can exhaust the Node.js call stack. No EPSS score, CISA KEV entry, or public POC was provided in the intelligence set, so there is no public exploit identified at time of analysis and no evidence of active exploitation. NOTE A CONFLICT: the input tag 'Information Disclosure' contradicts the CVSS vector, which shows zero confidentiality/integrity impact and only availability impact - the CWE-674 mechanism is a resource-exhaustion DoS, so the tag appears mislabeled and should not drive triage. Overall this warrants routine patching (trivial exploit, wide library footprint) rather than emergency response, because worst-case impact is a crashed request or process, not data loss. |
| Exploit ScenarioDerived | An attacker submits crafted HTML - for example through a comment, form field, or rich-text input that an application passes to sanitize-html with its default options - in which a disallowed <iframe> contains deeply nested raw-text content. Because the sanitizer recursively re-sanitizes that content without any depth bound, the Node.js call stack is exhausted, throwing a stack-overflow error that fails the request or can disrupt the service. No public exploit code was provided, but the trigger is simple to construct once the mechanism is known. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 20, 2026
Unbounded recursive re-sanitization in sanitize-html 2.18.0 allows remote attackers to exhaust the Node.js call stack and crash the process by submitting HTML containing a disallowed <iframe> with deeply nested raw-text content. The flaw triggers only under the library defaults - <iframe> absent from allowedTags and disallowedTagsMode set to 'discard' - which means most unmodified deployments, including ApostropheCMS installations that route untrusted HTML through the sanitizer, are exposed. Impact is limited to availability (CVSS 5.3, A:L only, PR:N/AC:L/UI:N) with no confidentiality or integrity effect, and no public exploit code or CISA KEV active-exploitation entry was identified at time of analysis.
RemediationAI
Vendor-released patch: sanitize-html 2.18.1 - upgrade the dependency to that version (release tag https://github.com/apostrophecms/apostrophe/releases/tag/sanitize-html@2.18.1) and, for ApostropheCMS deployments, update the CMS to a release containing commits 06e4b377f3c360f9e89c32dccd7e505ad5ddf498 and 40b989b1a9dd23d30029b8ce7668634265cfe5ea as described in advisory GHSA-c9rx-x947-fp3h; verify with a lockfile or dependency-tree audit since sanitize-html is often a transitive dependency. If immediate upgrade is not possible, the most targeted workaround is to set disallowedTagsMode to 'escape' (or 'recursiveEscape') in every sanitize-html options object, which bypasses the recursive re-sanitization path entirely; the trade-off is that disallowed tags are rendered as visible escaped text rather than silently stripped, which can change page output and, for content like malformed markup, expose raw angle brackets to readers. A secondary compensating control is to reject or strip <iframe> blocks and cap input length before HTML reaches the sanitizer, trading completeness for reduced attack surface, and to run sanitization in a worker/child process so a stack overflow does not take down the main HTTP process. Do not simply add <iframe> to allowedTags as a fix - it re-enables iframe-based content injection risks that the default configuration was designed to avoid.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 packages in npm, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
sanitize-html is an npm package built on the htmlparser2 parser and is widely used, directly or transitively, by Node.js frameworks and CMSs. The affected CPE strings cover both apostrophecms:apostrophe and apostrophecms:sanitize-html, reflecting that the library ships inside ApostropheCMS as well as standalone. Under CWE-674 (Uncontrolled Recursion), when a tag is disallowed and disallowedTagsMode is 'discard' (both defaults), sanitize-html treats the content of raw-text elements such as <iframe> as text that must itself be re-sanitized, invoking sanitizeHtml(text, options) recursively. Each nested invocation initializes a fresh parser and state rather than inheriting a shared depth counter, so there is no ceiling on recursion depth and no accumulated state that would cut it off; sufficiently deep nesting overflows the V8 call stack and throws a RangeError. Because Node.js serves requests on a single event-loop thread, an uncaught stack overflow from a request-scoped sanitize call can abort the request or the worker process, producing the assessed availability-only impact. Deployments that explicitly allow iframes, or that set disallowedTagsMode to 'escape'/'recursiveEscape', never enter the recursive code path.
Know when Apostrophecms gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Remotely reachable HTML input with no privileges or interaction (AV:N/AC:L/PR:N/UI:N); unbounded recursion causes stack exhaustion yielding only availability loss (A:L), with no confidentiality or integrity impact.
Primary rating from Vendor (GitHub_M).
CVSS VectorVendor: GitHub_M
Lifecycle Timeline
2DescriptionCVE.org
ApostropheCMS is an open-source Node.js content management system. In sanitize-html 2.18.0, when an <iframe> is not allowed and disallowedTagsMode is 'discard' (the defaults), its raw-text content is re-sanitized by a recursive call to sanitizeHtml(text, options). The recursion has no bound and starts each nested call with a fresh state. This vulnerability is fixed in 2.18.1.
Blast Radius
ecosystem impact- 108 npm packages depend on sanitize-html (28 direct, 83 indirect)
Ecosystem-wide dependent count for version 2.18.0.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
More in Apostrophecms
View allIntegrity bypass in ApostropheCMS page management allows authenticated low-privileged editors to move pages into restric
Stored cross-site scripting in ApostropheCMS prior to 2.17.6 enables execution of arbitrary JavaScript in victim browser
'sanitize-html' prior to version 1.0.3 is vulnerable to Cross-site Scripting (XSS). Rated medium severity (CVSS 6.1), th
`sanitize-html` prior to version 2.0.0-beta is vulnerable to Cross-site Scripting (XSS). Rated medium severity (CVSS 6.1
Apostrophe CMS versions prior to 3.3.1 did not invalidate existing login sessions when disabling a user account or chang
Stored XSS in sanitize-html versions 1.9.0 through 2.17.6 allows authenticated low-privileged users to inject executable
Versions of the package sanitize-html before 2.12.1 are vulnerable to Information Exposure when used on the backend and
Apostrophe Technologies sanitize-html before 2.3.2 does not properly validate the hostnames set by the "allowedIframeHos
Apostrophe Technologies sanitize-html before 2.3.1 does not properly handle internationalized domain name (IDN) which co
Prototype pollution in ApostropheCMS versions up to and including 4.30.0 allows an authenticated editor to poison Object
Stored cross-site scripting in the @apostrophecms/seo plugin (versions ≤1.4.2) allows any user holding the default edito
Stored cross-site scripting in ApostropheCMS SEO fields permits an authenticated attacker to inject arbitrary JavaScript
EUVD-2026-105176
GHSA-c9rx-x947-fp3h
NVD
CVE.org
EPSS
VulDB
Exploit-DB