BYBOWU > Blog > Web development

The expr‑eval Vulnerability: Fix It This Week

blog hero image
A critical flaw in expr‑eval (CVE‑2025‑12735) puts apps that evaluate user‑supplied formulas at risk of remote code execution. It lands the same month npm tightens tokens and pushes teams toward Trusted Publishing—so you’re juggling a code fix and a CI change at once. This field guide shows how to find expr‑eval in your stack fast, pick a safe remediation path, and lock down your pipeline so the next library incident doesn’t turn into a release‑day incident.
📅
Published
Nov 22, 2025
🏷️
Category
Web development
⏱️
Read Time
11 min

The expr‑eval vulnerability is the kind of bug that turns a quiet Friday into a war room. Tracked as CVE‑2025‑12735 and cataloged in the GitHub advisory database (GHSA‑jc85‑fpwf‑qm7x), it enables remote code execution when expr‑eval evaluates attacker‑influenced input. The original package hasn’t shipped a fix; the widely used fork has released breaking changes to close the hole. Meanwhile, npm’s November changes to tokens and publishing mean your mitigation may collide with CI. Let’s triage, fix, and harden—this week.

Terminal and code editor showing commands to locate expr‑eval

What changed in November 2025—and why it matters

Two threads converged this month. First, a critical expr‑eval bug landed public on November 4–5, 2025. The library has roughly 750k–800k weekly downloads and more than 250 dependents, so the blast radius is real. Second, npm tightened authentication and token policies across November 5 and November 19: classic tokens are gone, write‑scoped granular tokens rotate faster, and local publishing is shifting to short‑lived sessions with stronger 2FA. Trusted Publishing via OIDC is now mainstream. Translation: you must remediate code and modernize CI in the same sprint.

What is the expr‑eval vulnerability (CVE‑2025‑12735)?

expr‑eval is a JavaScript expression parser/evaluator—handy for calculators, rules engines, spreadsheet‑like fields, or AI‑adjacent tools that accept user formulas. The vulnerability stems from insufficient input validation in the evaluation path. If an attacker can influence the variables object passed to evaluate(), they can smuggle function objects or otherwise escape the intended sandbox and execute arbitrary code in your runtime.

Why it’s dangerous in practice

Developers often treat “math expression” parsers as safe compared to eval(). That assumption breaks here. On servers (Node.js, server‑side rendering, or background workers), arbitrary code execution is a straight path to secrets, database access, or lateral movement. On the client, the risk profile is different—still serious if you share a session context, embed privileged iframes, or evaluate in extensions or Electron. The hazard spikes anywhere the same process also manages credentials, cloud SDKs, or signing keys.

Patch status: original vs. fork

As of late November 2025, the original expr‑eval package’s latest published version remains 2.0.2, with no fixed release. There’s an open pull request in the upstream repository but it has not been shipped to npm. The actively maintained fork shipped a breaking security release (3.0.0) that changes how custom functions are registered: you can no longer sneak functions through the variables context; they must be explicitly registered on Parser.functions or similar. Expect small refactors when you migrate.

Am I affected? A 30‑minute triage workflow

Here’s a fast path to clarity. You’re done when you know (a) where expr‑eval sits (direct vs. transitive), (b) who feeds it input, and (c) whether that input can be influenced by an attacker.

1) Locate the package with your package manager

Use the commands your team actually runs in CI. Capture the output in your ticket.

npm: npm ls expr-eval expr-eval-fork

pnpm: pnpm why expr-eval

yarn classic: yarn why expr-eval

If you don’t see a direct dependency, check lockfiles for transitive inclusion. Grep is fine: grep -R "expr-eval" package-lock.json pnpm-lock.yaml yarn.lock.

2) Search your code for usage patterns

Look for new Parser(), Parser.parse(), and especially evaluate(variables). Audit who builds that variables object. Anything derived from user input, external webhooks, CSV uploads, or admin‑configurable formulas is suspect.

3) Threat‑model the call sites

For each call site, answer three questions: Can an external party influence the variables? Does evaluation run server‑side? Does the process hold secrets or privileged file/network access? If you hit two yeses, treat it as high risk and prioritize an immediate mitigation.

4) Freeze dangerous pathways

Until you patch or migrate, freeze releases that add new expr‑eval entry points. Consider temporarily disabling features that accept arbitrary formulas from users you don’t authenticate strongly.

Mitigation options: patch, migrate, or sandbox

There are three viable paths. Pick based on your risk tolerance, time pressure, and codebase size.

Option A: Migrate to the fork’s fixed release

Upgrade to expr-eval-fork at 3.0.0+ and refactor custom function registration. The fork moves function exposure to an explicit allowlist. This is the cleanest fix for long‑term maintenance, and it preserves the familiar API for most math use cases.

Typical changes include:

  • Stop passing functions in the variables map; register them on the parser instead: parser.functions.myFn = (x) => ....
  • Review any code that references object members or prototype paths within expressions—tightened semantics can surface latent assumptions.
  • Re‑run unit tests that exercise user‑defined formulas. Add tests that assert functions can’t be introduced via variables.

Option B: Replace expr‑eval entirely

If you only need a subset of math and can’t accept any expression engine risk, consider replacing the library with precompiled business rules or a constrained evaluator that doesn’t support user functions at all. This often reduces flexibility but slashes attack surface. It’s a strong choice for finance‑adjacent workflows, export pipelines, or anywhere a formula bug becomes a data‑integrity incident.

Option C: Temporary sandboxing and guards

When migration can’t land this week, add guardrails now:

  • Validate and sanitize the variables object before evaluation. Reject objects that contain functions, getters/setters, or unexpected prototypes. Shallow clone with Object.create(null) to drop prototype chains.
  • Run expression evaluation in a worker thread or separate process with minimal privileges and a strict resource budget. Kill long‑running parses. Cap expression length and nested calls.
  • For server‑side apps, isolate evaluation from secrets and file system access. Disable environment variable reads in that process, and keep network clients out of scope.

These are stopgaps, not substitutes for a proper library upgrade.

Secure your pipeline before attackers do

exploits increasingly target publishing and CI secrets, not just runtime bugs. The November npm changes push the ecosystem toward better defaults: classic tokens revoked; write‑scoped granular tokens with short lifetimes; and stronger 2FA for local publishing. Trusted Publishing via OIDC (available since mid‑2025) lets you publish without storing an npm token at all. If your fix requires shipping new packages, modernize your pipeline while you’re in there.

Minimal viable CI hardening this week

  1. Rotate off classic tokens. If your pipeline still uses NPM_TOKEN from the "classic" era, replace it with a granular token—or better, adopt Trusted Publishing.
  2. Adopt Trusted Publishing where possible. Configure a trusted publisher for your package and grant your GitHub Actions workflow OIDC. The npm CLI (v11.5.1+) will emit provenance by default.
  3. If you must use a token, enforce 2FA for local/manual publishing, and set a short expiry for write‑scoped granular tokens. Plan rotation on a calendar, not "later".
  4. Scan before publish. Add an npm audit or SCA step that fails the build on critical vulns, and diff your lockfile to catch surprise transitive pulls.

If you need a detailed playbook for the token cutover and OIDC setup, read our practical guide: a 7‑day npm token cutover plan.

The quick‑hit checklist (copy into your incident ticket)

Use this to move from “we heard about it” to “we shipped the fix.”

  1. Inventory: Run npm ls/pnpm why/yarn why for expr-eval and the fork. Save output.
  2. Usage map: Find all evaluate() call sites and the code paths that build variables.
  3. Risk tag: Mark server‑side usage with attacker‑influenced input as High; client‑only as Medium unless privileged context exists.
  4. Mitigation: Choose A (migrate to expr-eval-fork@^3), B (replace), or C (temporary sandbox/guards).
  5. Tests: Add tests that prove functions can’t be injected via variables.
  6. CI: Move to Trusted Publishing or rotate tokens and enforce 2FA. Add a pre‑publish audit step.
  7. Observability: Add feature flags or metrics around expression use; alert on unusual expression size or error spikes.
  8. Comms: Post a concise RCA once fixed. If you accept formula input from customers, notify them of any behavior changes.

People also ask

Is expr‑eval still safe to use?

If you remain on the original package (≤2.0.2), you’re exposed. The safer path is to migrate to the maintained fork’s fixed release or replace the dependency. If you must stay temporarily, enforce strict guards around the variables object and isolate evaluation in a low‑privilege context.

Does this impact client‑side apps?

Yes, but the impact depends on what the app can access. In a vanilla browser tab with no elevated capabilities, the risk is lower than on a Node server. That said, browser extensions, Electron apps, kiosk environments, and any app that stores tokens locally in the same process raise the stakes. Treat those as high risk.

How do I check transitive dependencies?

Lockfiles tell the truth. Search your lockfile for expr-eval and re‑resolve with your package manager’s "dedupe" or resolution overrides if a transitive brings in the vulnerable package. Consider using an overrides field (npm overrides, pnpm pnpm.overrides, Yarn resolutions) to pin safe versions of the fork where supported.

What breaks when migrating to the fork?

Most math works as before. If you used to pass functions via the variables map, you must register them on the parser, and you may need to revisit expression strings that referenced object members beyond a documented allowlist. The breaking changes are security‑motivated; keep your tests close as you move.

A practical migration pattern

Here’s a tiny before/after to help your team unblock reviews.

Before (vulnerable pattern): const parser = new Parser(); parser.parse(expr).evaluate({ f: (x) => dangerous(x), x: 2 })

After (fork ≥3.0.0): const parser = new Parser(); parser.functions.f = (x) => safe(x); parser.parse(expr).evaluate({ x: 2 })

Pair this with a defensive wrapper that rejects non‑primitive values in variables and caps expression size. If you serve multi‑tenant users, consider per‑tenant allowlists for functions and constants.

Don’t ship a code fix and keep a leaky CI

Modern attacks chain vulnerabilities with weak pipelines. If an attacker can hijack a maintainer account or steal a long‑lived token, they don’t need your expr‑eval bug at all. That’s why npm is forcing the issue on tokens, lifetimes, and 2FA—and why OIDC Trusted Publishing is the right default for 2025. If you haven’t set it up yet, this is the week.

Also audit your GitHub Actions permissions. For PRs from forks, disable privileged tokens, scrutinize composite actions, and get pull_request_target usage right. The same mindset that prevents supply‑chain worms will limit damage if a dependency ever goes sideways again.

CI pipeline using OIDC Trusted Publishing instead of long‑lived tokens

Risks, limits, and edge cases you should know

There’s always fine print. A few notes from shipping these fixes with teams this month:

  • Don’t rely on WAF rules alone. Obfuscated payloads and odd object shapes can bypass naive filters. Treat WAF as supplemental.
  • SSR frameworks can blur server/client boundaries. If your Next/Nuxt/SvelteKit code evaluates expressions during pre‑render, that’s server‑side exposure, even if it “feels” client‑only.
  • Electron, Tauri, and extension contexts deserve special handling. Lock down IPC bridges and background scripts if expressions run there.
  • Monitoring helps. Track expression length, parse time, and error counts. Alert on deviations; attackers often probe for sandbox edges before they try real payloads.

What to do next (today, tomorrow, next sprint)

Today: Run the triage commands, tag risk, decide A/B/C, and freeze unsafe features. If CI still uses classic tokens, start the switch immediately.

Tomorrow: Land the migration to the fork or a replacement, add tests to block function injection, and turn on Trusted Publishing with provenance. Document the change for support and customer success.

Next sprint: Add pre‑publish SCA checks, codify variable sanitization, and audit PR workflows for secrets exposure. If you want a second set of eyes on design or implementation, our team can help you secure build pipelines and perform app security reviews.

Team whiteboard with phased remediation plan

Zooming out

Here’s the thing: supply‑chain incidents are now the norm, not the exception. The expr‑eval vulnerability is a harsh reminder that “safe” parsing code can become unsafe overnight. The fix isn’t only a version bump; it’s a habit change—explicit allowlists for capabilities, short‑lived credentials in CI, and fewer secrets in memory. Do that, and the next headline becomes a routine patch, not a breach.

If you’re juggling this alongside other roadmap work and need focused help, we’ve done this dance before. Browse a few recent engineering briefs on our blog, or get in touch if you want us to help scope the upgrade and rollout.

Written by Viktoria Sulzhyk · BYBOWU
2,778 views

Get in Touch

Ready to start your next project? Let's discuss how we can help bring your vision to life

Email Us

[email protected]

We'll respond within 24 hours

Call Us

+1 (602) 748-9530

Available Mon-Fri, 9AM-6PM

Live Chat

Start a conversation

Get instant answers

Visit Us

Phoenix, AZ / Spain / Ukraine

Digital Innovation Hub

Send us a message

Tell us about your project and we'll get back to you

💻
🎯
🚀
💎
🔥