CVE-2026-113654

mediumpriority · track · 0EPSS 0.003 · 28 %ileUS
grimoire priorityP3 · Track
Exploitable?
—
no known exploitation
Likely / severe?
0.35% (28th) EPSS
CVSS 5.3 · medium
Is it mine?
1 products
Check your exposure
Who says so?
1 sources
osv

EPSS · scored 2026-10-28

ApostropheCMS is an open-source Node.js content management system, and sanitize-html provides a simple HTML sanitizer with a clear API. Prior to sanitize-html 2.18.0, a non-default nonTextTags configuration that includes noscript can end its discard region early when htmlparser2 emits an implied ancestor close inside noscript. Because scripting-enabled browsers treat noscript content as raw text while the parser does not model that mode, content intended to remain inert can survive sanitization and render; the issue does not generalize to every default nonTextTags element. This issue is fixed in sanitize-html 2.18.0.

01

cvss

Technical severity, 0–10. One row per scoring source.

5.3
010

base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · low–medium · 1.3–5.3

v4.05.3mediumCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Xsecondary · security-advisories@github.com
v4.01.3lowCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Xsecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: poc · Automatable: no · Technical Impact: partialcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (1)

Products and version ranges known to be affected.

05

advisories (1)

Vendor and ecosystem advisories describing this.

  • GHSA-x3q4-9hxx-gx8mApostropheCMS sanitize-html: nonTextTags discard region ends early on an implied close, letting <noscript> content render2026-10-20ghsa · osvUS

    ## Summary `sanitize-html` discards the *content* of every element in `nonTextTags`. It delimits that region using htmlparser2's close events, and ignores the `isImplied` flag htmlparser2 passes it. Closing a still-open **ancestor** from inside a `<noscript>` makes htmlparser2 unwind its stack past the `noscript`; the synthetic implied close it emits on the way ends the discard region early, and everything after it is treated as ordinary body content. A browser with scripting enabled parses `<noscript>` content as **raw text**, so the same markup renders as inert text there. The sanitizer therefore emits elements the page itself would not have. ## Reproduction ```js const sanitizeHtml = require("sanitize-html"); sanitizeHtml('<div><noscript></div><img src="http://evil.test/t.gif"></noscript>', { allowedTags: ["div", "img"], allowedAttributes: { img: ["src"] }, nonTextTags: ["script", "style", "textarea", "option", "noscript"], }); // => '<div></div><img src="http://evil.test/t.gif" />' ``` Chrome, given the same input, renders **no** `<img>` — the whole payload is raw text inside the unclosed `<noscript>`. Verified with Playwright, `srcdoc` into an iframe so the scripting flag is on. A `<![CDATA[` variant hides the opening tag from the parser entirely and has the same effect: ``` <p>Hi</p><![CDATA[ x > <noscript>]]><a href="…">Reset your password</a><img src="…beacon.gif"></noscript> ``` htmlparser2 runs a CDATA token to `]]>`; Chrome ends a bogus comment at the first `>`, so the `<noscript>` after it is real to the browser and invisible to the parser. ## Where the behaviour is `index.js`: - `:154` — `nonTextTagsArray` (the default list, `['script','style','textarea','option','xmp']`). - `:638` — `onclosetag: function (name, isImplied)` — receives the flag. - `:644` — `skipTextDepth--` — decrements without consulting `isImplied`. ## Suggested fix Do not end a discard region on an implied close. htmlparser2 already distinguishes them; the flag is passed and discarded. Something close to: ```js onclosetag: function (name, isImplied) { if (skipText) { if (isImplied) return; // an implied close must not end the region skipTextDepth--; … ```

06

sources

Which sources assert this record, and when.

published 2026-10-20modified 2026-10-28
07

references (4) nvd

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan