Remote Code Injection
Description
The package convert-svg-core before 0.6.2 are vulnerable to Remote Code Injection via sending an SVG file containing the payload.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
convert-svg-core before 0.6.2 is vulnerable to remote code injection via a crafted SVG file, allowing attackers to execute arbitrary code in the headless Chromium context.
Vulnerability
Overview
The convert-svg-core package, part of a monorepo for converting SVG files into other formats using headless Chromium, is vulnerable to remote code injection (RCE) in versions prior to 0.6.2 [1]. The root cause is the lack of input sanitization when processing SVG files. The package uses Cheerio to parse SVG content but did not strip dangerous attributes such as onload event handlers, which can contain arbitrary JavaScript [2]. When the SVG is rendered by headless Chromium, the injected script executes in the context of the browser process, leading to code execution on the server.
Exploitation
An attacker can exploit this vulnerability by sending a specially crafted SVG file containing malicious JavaScript payloads (e.g., via onload or other event attributes) to any application that uses the vulnerable package to convert SVG input [4]. No authentication is required if the application exposes an endpoint that accepts SVG files. The PoC provided by Snyk demonstrates sending an SVG to a convert-svg-to-png endpoint, which triggers the injection [4]. The headless Chromium instance then executes the injected script, allowing the attacker to run arbitrary commands.
Impact
Successful exploitation results in remote code execution on the server hosting the application. An attacker can execute arbitrary system commands, potentially leading to full compromise of the server, data exfiltration, or further lateral movement within the network. The vulnerability is rated with a high CVSS score due to the ease of exploitation and severe impact [1].
Mitigation
The vulnerability has been fixed in version 0.6.2 of convert-svg-core [2]. The fix introduces a sanitization step that removes dangerous attributes from the SVG input before rendering, effectively preventing script injection [2]. Users are strongly advised to upgrade to version 0.6.2 or later. No workarounds are available; upgrading is the only recommended mitigation [4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
convert-svg-corenpm | < 0.6.2 | 0.6.2 |
Affected products
2- convert-svg-core/convert-svg-coredescription
Patches
17e6031ac7427Strip onload attribute from SVG input
11 files changed · +21 −15
package-lock.json+1 −1 modified@@ -8,7 +8,7 @@ "license": "MIT", "dependencies": { "chalk": "^4.1.2", - "cheerio": "^1.0.0-rc.10", + "cheerio": "^1.0.0-rc.11", "commander": "^9.2.0", "file-url": "^3.0.0", "get-stdin": "^8.0.0",
packages/convert-svg-core/package.json+1 −1 modified@@ -36,7 +36,7 @@ }, "dependencies": { "chalk": "^4.1.2", - "cheerio": "^1.0.0-rc.10", + "cheerio": "^1.0.0-rc.11", "commander": "^9.2.0", "file-url": "^3.0.0", "get-stdin": "^8.0.0",
packages/convert-svg-core/src/Converter.js+13 −13 modified@@ -47,6 +47,7 @@ const _parseOptions = Symbol('parseOptions'); const _provider = Symbol('provider'); const _roundDimension = Symbol('roundDimension'); const _roundDimensions = Symbol('roundDimensions'); +const _sanitize = Symbol('sanitize'); const _setDimensions = Symbol('setDimensions'); const _tempFile = Symbol('tempFile'); const _validate = Symbol('validate'); @@ -114,9 +115,7 @@ class Converter { options = this[_parseOptions](options); - const output = await this[_convert](input, options); - - return output; + return await this[_convert](input, options); } /** @@ -191,11 +190,13 @@ class Converter { input = Buffer.isBuffer(input) ? input.toString('utf8') : input; const { provider } = this; - const svg = cheerio.default.html(cheerio.load(input, null, false)('svg')); + const svg = cheerio.default.html(this[_sanitize](cheerio.load(input, null, false)('svg'))); + + if (!svg) { + throw new Error('SVG element not found in input. Check the SVG input'); + } - let html = ''; - if (svg) { - html += `<!DOCTYPE html> + const html = `<!DOCTYPE html> <html> <head> <base href="${options.baseUrl}"> @@ -207,9 +208,6 @@ html { background-color: ${provider.getBackgroundColor(options)}; } </head> <body>${svg}</body> </html>`; - } else { - throw new Error('SVG element not found in input. Check the SVG input'); - } const page = await this[_getPage](html); @@ -226,12 +224,10 @@ html { background-color: ${provider.getBackgroundColor(options)}; } await page.setViewport(dimensions); - const output = await page.screenshot(Object.assign({ + return await page.screenshot(Object.assign({ type: provider.getType(), clip: Object.assign({ x: 0, y: 0 }, dimensions) }, provider.getScreenshotOptions(options))); - - return output; } async [_getDimensions](page, options) { @@ -389,6 +385,10 @@ html { background-color: ${provider.getBackgroundColor(options)}; } }; } + [_sanitize](svg) { + return svg.removeAttr('onload'); + } + async [_setDimensions](page, dimensions) { if (typeof dimensions.width !== 'number' && typeof dimensions.height !== 'number') { return;
packages/convert-svg-test-helper/src/fixtures/input/issue-81.svg+1 −0 added@@ -0,0 +1 @@ +<svg viewBox="0 0 240 80" height="1000" width="1000" onload="eval(atob(this.id))" id="ZG9jdW1lbnQud3JpdGUoJzxzdmctZHVtbXk+PC9zdmctZHVtbXk+PGlmcmFtZSBzcmM9ImZpbGU6Ly8vZXRjL3Bhc3N3ZCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwMHB4Ij48L2lmcmFtZT48c3ZnIHZpZXdCb3g9IjAgMCAyNDAgODAiIGhlaWdodD0iMTAwMCIgd2lkdGg9IjEwMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRleHQgeD0iMCIgeT0iMCIgY2xhc3M9IlJycnJyIiBpZD0iZGVtbyI+ZGF0YTwvdGV4dD48L3N2Zz4nKTs="></svg>
packages/convert-svg-test-helper/src/tests.json+5 −0 modified@@ -163,6 +163,11 @@ "file": "cve-2021-23631.svg", "message": "should only read SVG element" }, + { + "name": "when SVG has onload attribute", + "file": "issue-81.svg", + "message": "should strip onload attribute" + }, { "name": "when setting both baseFile and baseUrl options", "file": "external-file.svg",
packages/convert-svg-to-jpeg/test/fixtures/expected/28.jpeg+0 −0 addedpackages/convert-svg-to-jpeg/test/fixtures/expected/35.jpeg+0 −0 removedpackages/convert-svg-to-jpeg/test/fixtures/expected/36.jpeg+0 −0 modifiedpackages/convert-svg-to-jpeg/test/fixtures/expected/37.jpeg+0 −0 modifiedpackages/convert-svg-to-jpeg/test/fixtures/expected/38.jpeg+0 −0 addedpackages/convert-svg-to-png/test/fixtures/expected/28.png+0 −0 added
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-5gxc-fxcr-9326ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-25759ghsaADVISORY
- github.com/neocotic/convert-svg/commit/7e6031ac7427cf82cf312cb4a25040f2e6efe7a5ghsax_refsource_MISCWEB
- github.com/neocotic/convert-svg/issues/81ghsax_refsource_MISCWEB
- github.com/neocotic/convert-svg/pull/82ghsax_refsource_MISCWEB
- security.snyk.io/vuln/SNYK-JS-CONVERTSVGCORE-2849633ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.