CVE-2026-84369 Overview
SVGO (SVG Optimizer) is a Node.js library and command-line tool used to optimize SVG files. CVE-2026-84369 affects the opt-in removeScripts plugin (named removeScriptElement in versions 2 and 3), which strips SVG and XHTML <script> elements but fails to inspect executable HTML content nested inside SVG <foreignObject> elements. Attackers can embed event-handler attributes such as onload and onbeforetoggle, srcdoc documents, and executable URLs in action, data, formaction, href, and src attributes. When an application relies on the plugin as its sole sanitization control and serves the optimized SVG in an active browser context, the payload executes in the viewer's origin. The issue affects versions 1.0.0 through 2.8.3, 3.3.4, and 4.0.x, and is fixed in 2.8.4, 3.3.5, and 4.1.0.
Critical Impact
Attacker-controlled SVG input can execute script in the viewer's origin, exposing session data, modifying page content, or performing actions as the victim.
Affected Products
- SVGO versions 1.0.0 through 2.8.3
- SVGO versions 3.0.0 through 3.3.4
- SVGO versions 4.0.0 through 4.0.x
Discovery Timeline
- 2026-09-01 - CVE-2026-84369 published to NVD
- 2026-09-02 - Last updated in NVD database
Technical Details for CVE-2026-84369
Vulnerability Analysis
CVE-2026-84369 is a Cross-Site Scripting (XSS) vulnerability [CWE-79] rooted in incomplete sanitization inside SVGO's script-removal plugin. The plugin was designed to remove <script> elements from the SVG and XHTML namespaces. However, SVG documents can embed arbitrary HTML through the <foreignObject> element, and the plugin did not descend into that content to strip HTML-native execution vectors.
As a result, DOM event handlers such as onload, onerror, and onbeforetoggle, along with <iframe srcdoc="..."> documents and executable-scheme URLs in attributes such as href, src, action, data, and formaction, survive the optimization pass. Applications that treat SVGO output as safe-for-rendering inherit an active XSS sink.
Root Cause
The plugin's namespace filter only recognized http://www.w3.org/2000/svg and http://www.w3.org/1999/xhtml script contexts. It did not process HTML content nested inside <foreignObject>, nor did it validate URL-bearing attributes for javascript: or vbscript: schemes. Sanitization was structural (element name based) rather than behavioral (attribute and URL scheme based).
Attack Vector
An attacker submits a crafted SVG to an application that runs SVGO with the removeScripts (or removeScriptElement) plugin and later renders the optimized output inline in a browser. Because the plugin does not strip foreignObject-scoped event handlers or executable URLs, the browser executes the payload in the origin serving the SVG. Exploitation requires user interaction to load or view the SVG.
// Patch excerpt from lib/svgo/tools.js
// Introduces URL-scheme validation for executable content
const executableDataMediaTypes = new Set([
'application/xhtml+xml',
'image/svg+xml',
'text/html',
]);
/**
* Check whether a URL can contain executable content in a browser.
*/
const isExecutableUrl = (value) => {
const normalizedValue = value
.replace(/[\t\n\r]/g, '')
.trimStart()
.toLowerCase();
if (
normalizedValue.startsWith('javascript:') ||
normalizedValue.startsWith('vbscript:')
) {
return true;
}
// ...
};
// Source: https://github.com/svg/svgo/commit/994a9f00d79ddec68ce19a1ce9eb8ca08d747e4f
// Patch excerpt from plugins/removeScripts.js
// Adds foreignObject-aware namespace handling and HTML URL attribute set
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
/** Namespaces that support SVG <foreignObject> elements. */
const FOREIGN_OBJECT_NAMESPACES = [SVG_NAMESPACE];
/** Namespaces that support executable <script> elements. */
const SCRIPT_NAMESPACES = [SVG_NAMESPACE, 'http://www.w3.org/1999/xhtml'];
/** Attributes that can load or navigate to executable documents in HTML. */
const HTML_URL_ATTRS = new Set(['action', 'data', 'formaction', 'href', 'src']);
// Source: https://github.com/svg/svgo/commit/fd51e474a300417d9361d9302d596b1763146327
Detection Methods for CVE-2026-84369
Indicators of Compromise
- SVG files containing <foreignObject> elements with embedded HTML event handlers such as onload, onerror, or onbeforetoggle.
- SVG files with <iframe> elements using srcdoc attributes, or anchor and form elements whose href, src, action, formaction, or data attributes begin with javascript: or vbscript:.
- Web server logs showing uploads of SVG assets from untrusted users followed by outbound requests to attacker-controlled domains.
Detection Strategies
- Inventory Node.js projects and static build pipelines that depend on svgo versions earlier than 2.8.4, 3.3.5, or 4.1.0 by scanning package.json and lockfiles.
- Add pre-render validation that rejects SVG content containing foreignObject, iframe, or attributes whose values match ^\s*(javascript|vbscript):.
- Correlate content-type mismatches where user-supplied SVGs are served with an active image/svg+xml context inside first-party origins.
Monitoring Recommendations
- Alert on browser Content Security Policy (CSP) violations reported from pages that render user-supplied SVGs.
- Monitor upload endpoints for SVG payloads that include <foreignObject>, srcdoc, or executable URL schemes.
- Track dependency drift so downstream packages that bundle SVGO also receive the fixed release.
How to Mitigate CVE-2026-84369
Immediate Actions Required
- Upgrade SVGO to 2.8.4, 3.3.5, or 4.1.0 depending on the major version in use.
- Audit all transitive dependencies (build tools, image pipelines, CMS plugins) that ship SVGO and pull in the patched version.
- Do not treat SVGO output as a sanitizer of untrusted SVGs; combine it with a dedicated HTML/SVG sanitizer such as DOMPurify configured for SVG.
Patch Information
The SVGO maintainers released fixes in SVGO Release v2.8.4, SVGO Release v3.3.5, and SVGO Release v4.1.0. The hardening is described in SVGO Security Advisory GHSA-4vpr-x523-8j87 and delivered through Pull Request #2264, Pull Request #2269, and Pull Request #2272. The fixes add foreignObject traversal, a HTML_URL_ATTRS denylist, and the isExecutableUrl scheme check.
Workarounds
- Serve user-supplied SVGs from a sandboxed origin (separate hostname) with a restrictive Content Security Policy that blocks inline scripts and event handlers.
- Pass optimized SVG output through a downstream sanitizer such as DOMPurify with the USE_PROFILES: { svg: true, svgFilters: true } configuration.
- Where feasible, render user SVGs as <img src="data.svg"> or inside <object> tags rather than inlining, to block script execution contexts.
# Upgrade to a patched SVGO release
npm install svgo@^4.1.0
# Or for v3 branch
npm install svgo@^3.3.5
# Or for v2 branch
npm install svgo@^2.8.4
# Verify installed version
npm ls svgo
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.