CVE-2026-116582: Cross-Site Scripting via Unescaped RegExp Serialization in Seroval
Vulnerability ID: CVE-2026-116582
CVSS Score: 4.7
Published: 2026-10-28
CVE-2026-116582 is an improper output escaping vulnerability in the Seroval JavaScript serialization library that leads to cross-site scripting (XSS). When Seroval serializes RegExp objects into executable JavaScript literals for embedding in HTML script elements, it fails to neutralize the less-than character ('<'). If an application constructs a regular expression from untrusted input and embeds the serialized output inside an inline script block during server-side rendering (SSR), an attacker can inject a closing script tag to break out of the JavaScript context and execute arbitrary client-side code.
TL;DR
Seroval versions prior to 1.0.0 and from 1.5.5 to 1.6.9 fail to escape '<' characters when serializing RegExp objects into JavaScript literals. Embedding serialized untrusted RegExp objects into HTML blocks enables cross-site scripting (XSS). Upgrade to Seroval 1.6.10 to remediate the flaw.</p> <hr> <h3> <a name="exploit-status-poc" href="#exploit-status-poc" class="anchor"> </a> ⚠️ Exploit Status: POC </h3> <h2> <a name="technical-details" href="#technical-details" class="anchor"> </a> Technical Details </h2> <ul> <li><strong>CVE ID</strong>: CVE-2026-116582 (GHSA-9wx9-5pv9-3349)</li> <li><strong>Weakness Class</strong>: CWE-79 (Cross-Site Scripting) / CWE-116 (Improper Output Escaping)</li> <li><strong>CVSS v3.1 Score</strong>: 4.7 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N)</li> <li><strong>EPSS Score</strong>: 0.19% (8.36th Percentile)</li> <li><strong>Attack Vector</strong>: Network (SSR HTML <script> Breakout via RegExp Literal)</li> <li><strong>Affected Versions</strong>: seroval < 1.0.0 and >= 1.5.5, < 1.6.10</li> <li><strong>Patched Version</strong>: seroval 1.6.10</li> <li><strong>CISA KEV Status</strong>: Not Listed</li> </ul> <h2> <a name="affected-systems" href="#affected-systems" class="anchor"> </a> Affected Systems </h2> <ul> <li>seroval</li> <li>seroval-plugins</li> <li><strong>seroval</strong>: < 1.0.0 (Fixed in: <code>1.6.10</code>)</li> <li><strong>seroval</strong>: >= 1.5.5, < 1.6.10 (Fixed in: <code>1.6.10</code>)</li> <li><strong>seroval-plugins</strong>: < 1.0.0 (Fixed in: <code>1.6.10</code>)</li> <li><strong>seroval-plugins</strong>: >= 1.5.5, < 1.6.10 (Fixed in: <code>1.6.10</code>)</li> </ul> <h2> <a name="code-analysis" href="#code-analysis" class="anchor"> </a> Code Analysis </h2> <h3> <a name="commit-f94ee0b" href="#commit-f94ee0b" class="anchor"> </a> Commit: <a href="https://github.com/lxsmnsyc/seroval/commit/f94ee0b63936dae954ff50d5b5e8ea7cb9b284e6">f94ee0b</a> </h3> <p>fix: keep RegExp sources from closing the script element<br> </p> <div class="highlight"><pre class="highlight diff"><code><span class="gd">--- a/packages/seroval/src/core/context/serializer.ts </span><span class="gi">+++ b/packages/seroval/src/core/context/serializer.ts </span><span class="p">@@ -879,6 +879,13 @@</span> function serializeRegExp( node: SerovalRegExpNode, ): string { if (ctx.base.features & Feature.RegExp) { <span class="gi">+ // A literal would put the source's `<` back into the output, so `</script>` + // could close the page's script element. Escaping it inside a literal + // breaks named groups and lookbehinds, so the escaped source goes through + // the constructor instead. + if (node.c.includes('\\x3C')) { + return 'new RegExp("' + node.c + '","' + node.m + '")'; + } </span> return '/' + deserializeString(node.c) + '/' + node.m; } throw new SerovalUnsupportedNodeError(node); </code></pre></div> <p></p> <h2> <a name="mitigation-strategies" href="#mitigation-strategies" class="anchor"> </a> Mitigation Strategies </h2> <ul> <li>Upgrade the seroval package to version 1.6.10 or higher across all direct and transitive dependencies.</li> <li>Serialize user-supplied search or filter patterns as plain strings during SSR hydration and construct RegExp objects on the client side after deserialization.</li> <li>Implement a nonce-based Content Security Policy (CSP) without 'unsafe-inline' to prevent unauthorized inline <script> blocks from executing if script breakout occurs.</li> <li>Validate and reject untrusted regular expression patterns containing the '<' character before server-side instantiation.</li> </ul> <p><strong>Remediation Steps:</strong></p> <ol> <li>Audit application lockfiles (package-lock.json, pnpm-lock.yaml, yarn.lock) using 'npm ls seroval' to identify versions < 1.0.0 or >= 1.5.5, < 1.6.10.</li> <li>Run 'npm install seroval@^1.6.10' (or apply package.json overrides/resolutions for transitive dependencies) to install the patched release.</li> <li>Verify that serialized RegExp outputs containing '<' are now emitted as 'new RegExp("...\x3C...", "flags")' rather than literal '/.../' expressions.</li> <li>Redeploy the server-side rendering application and verify CSP headers are enforced on HTML responses.</li> </ol> <h2> <a name="references" href="#references" class="anchor"> </a> References </h2> <ul> <li><a href="https://github.com/lxsmnsyc/seroval/security/advisories/GHSA-9wx9-5pv9-3349">GitHub Security Advisory GHSA-9wx9-5pv9-3349</a></li> <li><a href="https://github.com/lxsmnsyc/seroval/commit/f94ee0b63936dae954ff50d5b5e8ea7cb9b284e6">Patch Commit: fix: keep RegExp sources from closing the script element</a></li> <li><a href="https://github.com/lxsmnsyc/seroval/releases/tag/seroval@1.6.10">GitHub Release: seroval@1.6.10</a></li> <li><a href="https://nvd.nist.gov/vuln/detail/CVE-2026-116582">National Vulnerability Database (NVD) - CVE-2026-116582</a></li> <li><a href="https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/116xxx/CVE-2026-116582.json">CVE Project cvelistV5 Record - CVE-2026-116582</a></li> <li><a href="https://www.cve.org/CVERecord?id=CVE-2026-116582">CVE.org Official Record - CVE-2026-116582</a></li> </ul> <hr> <p><em><a href="https://cvereports.com/reports/CVE-2026-116582">Read the full report for CVE-2026-116582 on our website</a> for more details including interactive diagrams and full exploit analysis.</em></p>
Top comments (0)