Cybersecurity

CVE-2026-40897: Arbitrary JavaScript Execution in Math.js Expression Parser

Team Nippysoft
18 min read
CVE-2026-40897: Arbitrary JavaScript Execution in Math.js Expression Parser

When a mathematics library trusted by millions of developers to perform safe, controlled expression evaluation becomes a vector for arbitrary JavaScript execution on the server, the consequences extend far beyond any single dependency update. CVE-2026-40897, published on April 24, 2026, documents precisely this scenario in Math.js, one of the most widely deployed mathematics libraries in the JavaScript and Node.js ecosystem. The National Vulnerability Database rates this flaw at CVSS 8.8 HIGH, with a vector that reflects low attack complexity, network accessibility, and full impact across confidentiality, integrity, and availability. The GitHub security advisory GHSA-29qv-4j9f-fjw5 is explicit: no workaround exists, and upgrading to version 15.2.0 is the only remediation available.

The vulnerable range spans Math.js versions 13.1.1 through 15.1.x. Any application that exposes the expression parser to user-controlled input while running within this range carries an active risk of remote code execution. The expression parser is not a peripheral feature of the library; it is central to Math.js and used extensively in production systems across education, analytics, engineering, and finance. The scale of adoption makes this a supply chain concern as much as a point vulnerability in a single dependency.

This analysis covers the technical mechanism of the flaw, the full CVSS vector, concrete production attack scenarios, the single most common architectural mistake that maximizes exposure, and the controls that should accompany the version upgrade as part of a complete response to this disclosure.

Math.js and the Expression Parser Attack Surface

Math.js has grown into the standard dependency for numerical computation in JavaScript applications. It provides symbolic mathematics, matrix operations, complex numbers, physical unit handling, and an expression parser that evaluates mathematical expressions given as strings at runtime. This combination makes it the default choice for scientific computing tools, educational platforms, analytics dashboards, financial modeling systems, and no-code application builders. The library is downloaded millions of times monthly from npm and appears as both a direct and transitive dependency across a broad segment of the JavaScript production ecosystem.

What the Expression Parser Does

The expression parser accepts a string such as 2 * x + sin(pi) and evaluates it against a configurable scope object provided by the developer. Applications use this capability to offer genuinely dynamic formula evaluation: users can write their own calculations without requiring the developer to anticipate every possible expression in advance.

Production use cases that commonly route user-controlled input through the expression parser include:

  • Online scientific calculators and interactive math tutoring environments
  • Analytics dashboards where users define custom computed metrics via formula editors
  • Engineering simulation tools that accept parameterized mathematical expressions
  • No-code and low-code platforms with spreadsheet-style formula evaluation
  • Financial modeling tools where users configure their own KPIs and derived metrics
  • Backend APIs that process expression-based filters or data transformation rules

In every one of these scenarios, the shared pattern is user-controlled input flowing into math.evaluate(), math.compile(), or a related API. That is the exact attack surface CVE-2026-40897 targets; it is not an edge case or unusual integration pattern but the primary documented use case for this feature.

The expression parser is a JavaScript-native evaluator operating within the same process as the host application. It is not an isolated interpreter running in a separate OS-level container. Any failure to contain the scope of what the parser can modify is a failure that occurs with the full privileges of the running Node.js process.

Parser Architecture and the Trust Boundary

Internally, the parser converts the input string into an Abstract Syntax Tree and traverses it to produce a result. Among the operations it processes are property assignments, function calls, index operations, and interactions with typed objects such as matrices and physical units. For safe operation under untrusted input, every operation that can interact with JavaScript's object model must be restricted to objects the library explicitly controls and introduces into the evaluation environment. Between versions 13.1.1 and 15.1.x, this restriction was incomplete for a specific class of property write operations: that gap is the root of CVE-2026-40897.

Technical Analysis of CVE-2026-40897

The vulnerability carries the classification CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes. This category describes cases where an application allows external input to determine both which object to target and which attribute to modify, without adequately restricting the set of objects that input can reach. The pattern is well understood in the context of prototype pollution attacks but applies equally to any expression evaluation system that supports dynamic property writes without sufficient scope enforcement.

How the Flaw Operates

Math.js's expression language supports assignment syntax. When the parser processes an expression that sets a property on an object, it must resolve the target object and apply the write. In a correctly sandboxed evaluator, this resolution would be strictly confined to objects explicitly provided by the developer in the evaluation scope. The flaw between versions 13.1.1 and 15.1.x permitted an attacker to craft an expression that, during evaluation, triggered a property setter on a JavaScript object outside the intended scope boundary.

Because the setter executes as standard JavaScript code, any logic attached to it runs with the same privileges as the Math.js evaluation context. In a Node.js server environment, the attacker's injected code runs server-side with full access to the Node.js process: environment variables, the file system, the network stack, in-memory credentials, and the broader runtime. This is a complete remote code execution scenario with no built-in mechanism limiting the blast radius once the setter is triggered.

The patch in version 15.2.0 (commit 513ab2a0e01004af91b31aada68fae8a821326ad, PR #3656) tightens the internal property write resolution logic so that only objects explicitly placed in the evaluation scope by the developer can have their attributes modified through expression assignment operations. The boundary absent in the vulnerable range is now enforced at the library level.

Practical scenario: An attacker with a basic user account submits a crafted expression targeting an internal JavaScript object via the property setter pathway. The server evaluates this expression during normal request processing. The attacker's code executes immediately with full process privileges: no additional steps required, no user interaction needed, no administrative access beyond a valid session.

CVSS 8.8 Vector Analysis

The full vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H aligns precisely with the attack mechanism:

  • AV:N (Attack Vector: Network): The malicious expression arrives as part of a standard HTTP request. No physical access or adjacent network position is required.
  • AC:L (Attack Complexity: Low): No race conditions, special system states, or prerequisite configurations are needed. A correctly formed expression string is the only requirement.
  • PR:L (Privileges Required: Low): Most applications that expose formula evaluation require a user account but not administrative access. A basic authenticated session is sufficient to launch the attack.
  • UI:N (User Interaction: None): The vulnerability fires when the server processes the expression. No other user or victim is required to take any action.
  • C:H / I:H / A:H: Code execution on the server means complete loss across all three security dimensions simultaneously.

The EPSS score of 0.051% (16th percentile) reflects the absence of widespread active exploitation at the time of initial disclosure. However, the combination of low attack complexity and network accessibility creates a short path from research-level technique to weaponized exploit.

CVE-2026-40897 — Math.js Expression Parser Attack FlowAttackerCrafted MathExpressionMath.jsExpression ParserAST EvaluationCWE-915Unsafe ObjectProperty SetterOut-of-scope WriteArbitrary JSExecution (RCE)Server-side CodeServer CompromisedC:H | I:H | A:HCVSS 8.8 HIGHFull Process AccessVulnerable: mathjs >= 13.1.1 and < 15.2.0 | Fixed: mathjs 15.2.0 | Commit: 513ab2a | PR #3656CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H | EPSS: 0.051% | Advisory: GHSA-29qv-4j9f-fjw5

Production Attack Scenarios

The abstract vulnerability becomes concrete when mapped onto the architectures where Math.js commonly appears in production. Three scenarios illustrate the realistic scope of exposure.

Educational Platform with a Live Expression Evaluator

An online math tutoring platform lets registered students submit expressions into a browser-based calculator. The Node.js backend receives the expression string and passes it directly to math.evaluate() on a server running Math.js 14.x. The platform considers account registration a sufficient access control. Under CVE-2026-40897, any student with a valid account can submit a crafted expression that executes arbitrary JavaScript on the application server. The attacker immediately gains access to session tokens of active users, database connection credentials stored in the process environment, and any API keys loaded as environment variables. Authentication provides no protection here; it satisfies PR:L, nothing more.

Analytics Dashboard with User-Defined Computed Metrics

Analytics platforms frequently let users write custom metric formulas. If Math.js is the server-side evaluation engine running on a version in the vulnerable range, the formula editor is an arbitrary code execution interface for any authenticated user. The severity in this scenario compounds because analytics platforms typically hold active integrations with data warehouses, cloud storage, third-party SaaS APIs, and internal services: all reachable once code executes on the compromised server.

Backend API Accepting Expression Parameters

Some backend services expose expression-based parameters for dynamic computation. If expressions from API callers reach Math.js without the application running version 15.2.0, every caller with a valid token is a potential attacker. In microservices environments the impact propagates: code executing inside a compromised service can reach internal services that trust the compromised component, enabling lateral movement across the infrastructure.

The common thread across all three scenarios is identical: user-controlled input reaches the Math.js expression parser on a Node.js server running a vulnerable version. The fix is the same regardless of application domain or scale.

Affected Versions and Patch Status

CVE-2026-40897 was introduced at Math.js version 13.1.1 and is present through every release up to and including 15.1.x. Version 15.2.0, released April 24, 2026, contains the complete fix. No partial mitigation, no configuration flag to disable the vulnerable behavior, and no workaround exists within the vulnerable range.

Version RangeStatusRecommended Action
Below 13.1.1Not affected by CVE-2026-40897Upgrade for unrelated security improvements
13.1.1 through 15.1.xVULNERABLE — CVSS 8.8 HIGHUpgrade to 15.2.0 immediately. No workaround exists.
15.2.0 and abovePatchedSafe. Monitor release notes for future updates.

Technical insight: Transitive dependencies require special attention. Run npm list mathjs --all to reveal every instance across all dependency levels, including nested ones invisible in the top-level package.json.

The Architectural Mistake That Maximizes Exposure

The most common mistake when integrating the Math.js expression parser is treating authentication as a sufficient security boundary for expression evaluation. The CVSS metric PR:L answers this directly: low privileges are all the attack requires. Requiring a login does not protect the server-side evaluator from a malicious user holding a valid account.

A closely related mistake is calling math.evaluate() with an excessively broad scope, or with no explicitly defined scope at all. Even after upgrading to the patched version, exposing the full Math.js function library to user-controlled expressions is poor practice. The attack surface of any expression evaluator scales directly with the richness of the scope it operates within.

Teams sometimes also assume that long-standing usage without incidents implies safety. CVE-2026-40897 was introduced at version 13.1.1 and may have been present in production deployments for an extended period before disclosure. Absence of reported incidents is not evidence of absence of exploitation.

Remediation and Architectural Hardening

The immediate fix is straightforward. The architectural hardening that should accompany it requires deliberate design decisions that outlast this specific vulnerability.

Upgrade to mathjs 15.2.0

# npm
npm install mathjs@15.2.0

# yarn
yarn add mathjs@15.2.0

# pnpm
pnpm add mathjs@15.2.0

Audit and Harden All Call Sites

  1. Search for every invocation of math.evaluate(), math.compile(), and math.parse() across the full codebase including wrapper functions and service layers.
  2. For each call site, trace the origin of the input. If any part can be influenced by a user, treat it as untrusted.
  3. Pass a minimal, explicitly constructed scope object to math.evaluate(). Include only what the specific use case requires.
  4. For high-risk contexts, use math.parse() to build the AST and inspect node types before calling evaluate(). Reject expressions that reference functions or operators the application does not need.

Combining scope restriction with AST inspection creates two independent barriers between user input and the evaluation engine. If either control is bypassed by a future vulnerability, the other remains active.

Performance and Scalability Considerations

Expression evaluation carries non-trivial overhead when called per-request. The standard optimization for high-throughput services is to use math.compile() to pre-compile expressions into callable function objects and cache them keyed by expression string. This avoids re-running AST construction and parse-time processing for recurring expressions.

The AST inspection step recommended for defense in depth adds minimal overhead: well under one millisecond for expressions of practical length. For services where expression evaluation is a throughput bottleneck, moving it off the synchronous request path into a worker thread or dedicated evaluation microservice is a sound architectural decision. It isolates the evaluation context from the main application, limits blast radius from any future vulnerability in this layer, and enables independent scaling of the computation tier.

Frequently Asked Questions

Does this vulnerability affect browser-only Math.js usage?

The critical risk is server-side deployment in Node.js. When Math.js runs entirely in the browser and no server-side evaluation occurs, an attacker exploiting this vulnerability executes code in their own browser session, not on shared infrastructure. Client-side usage does not carry the same remote code execution consequences, but upgrading is still recommended practice.

Is there any partial mitigation short of upgrading?

The GitHub security advisory explicitly states that no workaround exists and upgrading to 15.2.0 is mandatory. Application-level input validation may reduce the attack surface by rejecting some malicious expressions before they reach the parser, but it cannot reliably prevent exploitation of a flaw operating at the internal property write resolution level. Treat validation as a temporary measure alongside an expedited upgrade, not a substitute for it.

How do I confirm the installed version across all dependency levels?

Run npm list mathjs --all in the project directory. This lists every instance of the package across all dependency tree levels, including those pulled in transitively. If any instance shows a version between 13.1.1 and 15.1.x, and the application routes user input to the expression parser, the project is exposed.

Will upgrading to 15.2.0 break existing expressions?

The patch targets the internal property write resolution logic, not the public expression syntax. Applications that do not rely on the specific behavior the vulnerability exploits should continue evaluating expressions correctly after the upgrade. Run the existing test suite against 15.2.0 in a staging environment before deploying to production. PR #3656 describes the specific internal changes in full detail.

Conclusion

CVE-2026-40897 is a direct reminder that expression evaluation engines require both careful library design and disciplined integration practices. Math.js is a well-maintained library with an active community, and the prompt disclosure through GHSA-29qv-4j9f-fjw5, the public PR #3656, and the available fix commit reflect a security response process the ecosystem can rely on.

The response is two-part: upgrade to 15.2.0 without delay, and audit every call site where the expression parser receives user-influenced input. The upgrade closes the known vulnerability. The audit prevents the surrounding architecture from creating conditions for the next one.

Verify the installed version in every environment, push the upgrade through the deployment pipeline on the fastest available timeline, and treat scope restriction and input validation as non-negotiable defaults for any application evaluating user-provided expressions. Every hour the vulnerable version remains in production is unnecessary exposure to a CVSS 8.8 remote code execution risk.

References

Subscribe

Get the latest posts delivered right to your inbox.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Comments

No comments yet. Be the first to share your thoughts!

Subscribed!

Registered! A confirmation link has been sent to your email address. If you don't see it, please check your spam folder.

Error

An error occurred. Please try again.