Critical severity9.8GHSA Advisory· Published May 8, 2026· Updated May 12, 2026
CVE-2026-41507
CVE-2026-41507
Description
math-codegen generates code from mathematical expressions. Prior to version 0.4.3, string literal content passed to cg.parse() is injected verbatim into a new Function() body without sanitization. This allows an attacker to execute arbitrary system commands when user-controlled input reaches the parser. Any application exposing a math evaluation endpoint where user input flows into cg.parse() is vulnerable to full RCE. This issue has been patched in version 0.4.3.
Affected products
1- Range: < 0.4.3
Patches
14bb52d303068fix: improve code generation safety
7 files changed · +28 −6
lib/CodeGenerator.js+1 −1 modified@@ -79,7 +79,7 @@ CodeGenerator.prototype.compile = function (namespace) { ' $$processScope(scope)', ' ' + code, ' },', - " code: '" + code + "'", + ' code: ' + JSON.stringify(code), '}' ].join('\n')
lib/Interpreter.js+5 −0 modified@@ -21,6 +21,11 @@ const Interpreter = function (owner, options) { rawCallExpressionElements: false, applyFactoryToScope: false }, options) + + const factory = this.options.factory + if (typeof factory !== 'string' || !/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(factory)) { + throw new Error('factory must be a valid JS property access path (e.g. "ns.factory")') + } } extend(Interpreter.prototype, types)
lib/node/AssignmentNode.js+1 −1 modified@@ -1,5 +1,5 @@ 'use strict' module.exports = function (node) { - return 'scope["' + node.name + '"] = ' + this.next(node.expr) + return 'scope[' + JSON.stringify(node.name) + '] = ' + this.next(node.expr) }
lib/node/ConstantNode.js+2 −1 modified@@ -3,5 +3,6 @@ module.exports = function (node) { if (this.options.raw) { return node.value } - return this.options.factory + '(' + node.value + ')' + const value = node.valueType === 'string' ? JSON.stringify(node.value) : node.value + return this.options.factory + '(' + value + ')' }
lib/node/FunctionNode.js+1 −1 modified@@ -2,7 +2,7 @@ const SymbolNode = require('mr-parser').nodeTypes.SymbolNode const functionProxy = function (node) { - return '$$mathCodegen.functionProxy(' + this.next(new SymbolNode(node.name)) + ', "' + node.name + '")' + return '$$mathCodegen.functionProxy(' + this.next(new SymbolNode(node.name)) + ', ' + JSON.stringify(node.name) + ')' } module.exports = function (node) {
lib/node/SymbolNode.js+1 −1 modified@@ -2,5 +2,5 @@ module.exports = function (node) { const id = node.name - return '$$mathCodegen.getProperty("' + id + '", scope, ns)' + return '$$mathCodegen.getProperty(' + JSON.stringify(id) + ', scope, ns)' }
package-lock.json+17 −1 modified@@ -60,6 +60,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -736,6 +737,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1061,6 +1063,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001370", "electron-to-chromium": "^1.4.202", @@ -1748,6 +1751,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", "dev": true, + "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.1", "@humanwhocodes/config-array": "^0.10.4", @@ -1942,6 +1946,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -2008,6 +2013,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.5.tgz", "integrity": "sha512-8+BYsqiyZfpu6NXmdLOXVUfk8IocpCjpd8nMRRH0A9ulrcemhb2VI9RSJMEy5udx++A/YcVPD11zT8hpFq368g==", "dev": true, + "peer": true, "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", @@ -2060,6 +2066,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", "dev": true, + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2072,6 +2079,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.1.tgz", "integrity": "sha512-j4/2xWqt/R7AZzG8CakGHA6Xa/u7iR8Q3xCxY+AUghdT92bnIDOBEefV456OeH0QvBcroVc0eyvrrLSyQGYIfg==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0", @@ -6251,6 +6259,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "dev": true, + "peer": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -6779,7 +6788,8 @@ "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -7024,6 +7034,7 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "dev": true, + "peer": true, "requires": { "caniuse-lite": "^1.0.30001370", "electron-to-chromium": "^1.4.202", @@ -7537,6 +7548,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", "dev": true, + "peer": true, "requires": { "@eslint/eslintrc": "^1.3.1", "@humanwhocodes/config-array": "^0.10.4", @@ -7738,6 +7750,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -7794,6 +7807,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.2.5.tgz", "integrity": "sha512-8+BYsqiyZfpu6NXmdLOXVUfk8IocpCjpd8nMRRH0A9ulrcemhb2VI9RSJMEy5udx++A/YcVPD11zT8hpFq368g==", "dev": true, + "peer": true, "requires": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", @@ -7830,13 +7844,15 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", "dev": true, + "peer": true, "requires": {} }, "eslint-plugin-react": { "version": "7.31.1", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.1.tgz", "integrity": "sha512-j4/2xWqt/R7AZzG8CakGHA6Xa/u7iR8Q3xCxY+AUghdT92bnIDOBEefV456OeH0QvBcroVc0eyvrrLSyQGYIfg==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0",
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
5- github.com/mauriciopoppe/math-codegen/commit/4bb52d3030683362b3559ee8dd91350555a05f6bnvdPatch
- github.com/advisories/GHSA-p6x5-p4xf-cc4rghsaADVISORY
- github.com/mauriciopoppe/math-codegen/security/advisories/GHSA-p6x5-p4xf-cc4rnvdVendor Advisory
- github.com/mauriciopoppe/math-codegen/pull/11nvdIssue Tracking
- nvd.nist.gov/vuln/detail/CVE-2026-41507ghsa
News mentions
0No linked articles in our index yet.