Sorry, the diff of this file is too big to display
@@ -165,3 +165,3 @@ 'use strict'; | ||
| attrValue != null && | ||
| attrValue.trimStart().startsWith('javascript:'), | ||
| attrValue.trimStart().toLowerCase().startsWith('javascript:'), | ||
| ); | ||
@@ -168,0 +168,0 @@ |
+1
-1
| { | ||
| "packageManager": "yarn@2.4.3", | ||
| "name": "svgo", | ||
| "version": "3.3.3", | ||
| "version": "3.3.4", | ||
| "description": "Nodejs-based tool for optimizing SVG vector graphics files", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
@@ -18,3 +18,34 @@ 'use strict'; | ||
| /** Namespaces that support executable <script> elements. */ | ||
| const SCRIPT_NAMESPACES = [ | ||
| 'http://www.w3.org/2000/svg', | ||
| 'http://www.w3.org/1999/xhtml', | ||
| ]; | ||
| /** | ||
| * @param {string} elem | ||
| * @param {string} targetElem | ||
| * @param {ReadonlyMap<string, string[]>} prefixes | ||
| * @param {string[]} targetNamespaces | ||
| * @returns {boolean} | ||
| */ | ||
| function isNamespaceAwareElem(elem, targetElem, prefixes, targetNamespaces) { | ||
| if (elem === targetElem) { | ||
| return true; | ||
| } | ||
| if (elem.includes(':')) { | ||
| const [prefix, effectiveTag] = elem.split(':', 2); | ||
| if (targetElem === effectiveTag) { | ||
| const namespaces = /** @type {string[]} */ (prefixes.get(prefix)); | ||
| const namespace = namespaces[namespaces.length - 1]; | ||
| return targetNamespaces.includes(namespace); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Remove scripts. | ||
@@ -28,6 +59,30 @@ * | ||
| exports.fn = () => { | ||
| /** | ||
| * Map of XML namespace prefixes to the XML namespace. Each value is a stack | ||
| * as XML namespaces can be pushed to in children elements and revert back | ||
| * previous namespace when we exit that node. | ||
| * | ||
| * @type {Map<string, string[]>} */ | ||
| const prefixes = new Map(); | ||
| return { | ||
| element: { | ||
| enter: (node, parentNode) => { | ||
| if (node.name === 'script') { | ||
| for (const [k, v] of Object.entries(node.attributes)) { | ||
| if (!k.startsWith('xmlns:')) { | ||
| continue; | ||
| } | ||
| const prefix = k.slice(6); | ||
| if (!prefixes.has(prefix)) { | ||
| prefixes.set(prefix, [v]); | ||
| } else { | ||
| /** @type {string[]} */ (prefixes.get(prefix)).push(v); | ||
| } | ||
| } | ||
| if ( | ||
| isNamespaceAwareElem(node.name, 'script', prefixes, SCRIPT_NAMESPACES) | ||
| ) { | ||
| detachNodeFromParent(node, parentNode); | ||
@@ -44,2 +99,11 @@ return; | ||
| exit: (node, parentNode) => { | ||
| for (const k of Object.keys(node.attributes)) { | ||
| if (!k.startsWith('xmlns:')) { | ||
| continue; | ||
| } | ||
| const prefix = k.slice(6); | ||
| /** @type {string[]} */ (prefixes.get(prefix)).pop(); | ||
| } | ||
| if (node.name !== 'a') { | ||
@@ -53,3 +117,6 @@ return; | ||
| node.attributes[attr] == null || | ||
| !node.attributes[attr].trimStart().startsWith('javascript:') | ||
| !node.attributes[attr] | ||
| .trimStart() | ||
| .toLowerCase() | ||
| .startsWith('javascript:') | ||
| ) { | ||
@@ -56,0 +123,0 @@ continue; |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1496298
14.87%79
1.28%19279
14.19%13
8.33%