CVE-2025-12735 - expr-eval context function RCE
expr-eval is commonly used as the “safe math parser” replacement for
JavaScript eval(). CVE-2025-12735 is the uncomfortable edge case: vulnerable
versions can still reach attacker-influenced functions through the variables
object passed to evaluate(). If an application lets untrusted users submit
formula strings while the evaluator context contains callable values, object
members, request helpers, file helpers, shell wrappers, database clients, or
tenant-scoped service objects, the formula boundary can become code execution.
GitHub Advisory Database lists the original expr-eval package as affected
through 2.0.2 with no patched original-package version. It lists
expr-eval-fork as fixed in 3.0.1; do not stop at expr-eval-fork 3.0.0,
because that line was also marked affected. NVD/CISA-ADP scores
CVE-2025-12735 as Critical. NVD also tracks an adjacent original-package
prototype-pollution issue as CVE-2025-13204, so a mergeable PR should treat
original expr-eval replacement as the safer remediation shape even if the
scanner only reported one of the two CVEs.
When to use it
- A repository installs, vendors, bundles, or documents
expr-evalorexpr-eval-fork. - User-controlled formulas, rules, calculations, dashboards, reports, workflow
conditions, or templates reach
evaluate()with a variables/context object. - Evaluator context can contain functions, service clients, tenant objects, request objects, filesystem/process helpers, SDKs, loggers, or secrets.
- You need a bounded PR or triage note that replaces the vulnerable evaluator and reduces context objects to explicit inert data.
Inputs
- Package manifests, lockfiles, vendored bundles, Dockerfiles, generated dependency reports, SBOMs, evaluator imports, wrappers, and formula features.
- Expression ownership, server/browser reachability, variable-map construction, allowed formula identifiers, service/helper exposure, and logging behavior.
- Available package install, evaluator regression tests, lint/typecheck, build, container build, SBOM, and dependency/security scan commands.
Affected versions
- Vulnerable:
expr-eval <= 2.0.2. - No fixed original-package version: GitHub Advisory Database currently
lists no patched version for
expr-eval. - Vulnerable fork line:
expr-eval-fork <= 3.0.0. - Fixed fork line:
expr-eval-fork 3.0.1+. - Affected code shape: user-controlled expression strings are evaluated with a variables/context object that can contain functions, object members, privileged service clients, filesystem or process helpers, request helpers, tenant data, secrets, or other non-data objects.
- Fixed code shape: the expression evaluator is patched or replaced, and the evaluation context is reduced to explicit inert primitives or reviewed pure functions required for the formula use case.
Indicator-of-exposure
- The repository installs, vendors, bundles, or documents
expr-evalorexpr-eval-fork. - Formula, calculator, workflow-rule, pricing, report, analytics, low-code,
dashboard, feature-flag, policy, alerting, template, or user-defined field
features pass user-editable strings to
Parser.parse(...).evaluate(...),parser.evaluate(...), orExpression.evaluate(...). - The variables object is built from request bodies, database records, tenant configuration, workflow context, plugin state, object spreads, or service containers instead of a minimal literal map.
- The variables object contains functions, class instances, object members,
proxies, methods, module exports,
fs,process,child_process, network clients, database clients, queue clients, logger objects, SDK clients, or secrets. - Server-side use is reachable by anonymous, authenticated, cross-tenant, customer, marketplace, webhook, or integration input.
Quick checks:
rg -n "expr-eval|expr-eval-fork|new Parser\\(|Parser\\.parse|\\.evaluate\\(|parser\\.evaluate|Expression\\.evaluate" .
npm ls expr-eval expr-eval-fork
pnpm why expr-eval expr-eval-fork
yarn why expr-eval expr-eval-fork
Windows:
rg -n "expr-eval|expr-eval-fork|new Parser\(|Parser\.parse|\.evaluate\(|parser\.evaluate|Expression\.evaluate" .
npm ls expr-eval expr-eval-fork
pnpm why expr-eval expr-eval-fork
yarn why expr-eval expr-eval-fork
Do not validate exposure by running formulas that spawn processes, write files, read secrets, issue network requests, or touch production data.
Remediation strategy
- Remove the original
expr-evalpackage from controlled manifests, lockfiles, vendored bundles, generated dependency reports, SBOMs, container layers, and examples. Replace it withexpr-eval-fork 3.0.1+only when the fork’s API and breaking changes are compatible with the application. - If the application only needs a small formula language, consider replacing the dependency with a purpose-built parser or typed rule interpreter instead of carrying a general evaluator.
- Do not rely on a package bump alone. Patch evaluator call sites so the
variables object is built from an explicit allowlist of primitive values and
reviewed pure functions. Do not pass request objects, service containers,
SDK clients, module exports, ORM models, loggers, filesystem helpers, process
helpers, or tenant context objects into
evaluate(). - Reject or normalize formula identifiers before evaluation. Block member-path
access to dangerous names such as
constructor,prototype,__proto__,process,globalThis,require,module,exports, and any application helper that performs I/O or state changes. - Add a compatibility layer if renaming
expr-evalimports toexpr-eval-forkwould otherwise cause a broad application diff. The compatibility layer should expose only the parser features this product uses. - Add safe regression tests using local fixtures: a legitimate formula still evaluates, direct calls to non-allowlisted functions fail, nested member calls fail, prototype-pollution-style property names fail, and no test creates files, launches commands, opens sockets, or reads real secrets.
- If an exposed server-side formula surface evaluated untrusted input while the process held secrets or tenant data, patch first, then review logs and rotate reachable credentials according to the service incident policy.
The prompt
Model context: this prompt was generated by GPT 5.5 Extra High reasoning.
You are remediating CVE-2025-12735 / GHSA-jc85-fpwf-qm7x, the critical
`expr-eval` context-function code-injection issue. Also check the adjacent
original-package prototype-pollution CVE-2025-13204 when `expr-eval` is
present. Produce exactly one output:
- A reviewer-ready PR/change request that replaces vulnerable evaluator
versions, narrows all evaluator contexts to inert allowlisted data, adds safe
regression tests, refreshes generated artifacts, and documents operator
follow-up, or
- TRIAGE.md if this repository does not control an affected package, lockfile,
formula feature, runtime evaluator call site, generated artifact, or
deployment surface.
## Rules
- Scope only CVE-2025-12735, directly related `expr-eval` or
`expr-eval-fork` remediation, adjacent CVE-2025-13204 exposure when the
original package is present, evaluator context hardening, and generated
artifact refreshes.
- Treat request bodies, formulas, variables objects, tenant config, workflow
state, service clients, filesystem helpers, shell helpers, SDK clients,
credentials, secrets, logs, and evaluator errors as sensitive.
- Do not generate, run, preserve, publish, or link live RCE payloads.
- Do not prove exposure by spawning processes, writing files, reading local
files, opening sockets, making outbound requests, or touching production
data.
- Do not replace a vulnerable evaluator with JavaScript `eval()`, `new
Function()`, Node `vm`, or a broader template engine.
- Do not auto-merge.
## Steps
1. Inventory every JavaScript/TypeScript workspace, package manifest, lockfile,
vendored bundle, generated dependency report, SBOM, Dockerfile,
devcontainer, and deployment artifact controlled by this repository.
2. Find every reference to `expr-eval`, `expr-eval-fork`, `new Parser(...)`,
`Parser.parse(...)`, `parser.evaluate(...)`, and
`Expression.evaluate(...)`.
3. Resolve actual installed versions from lockfiles and package-manager
output. Mark a target vulnerable when it resolves `expr-eval <= 2.0.2`,
any original `expr-eval` line without a reviewed downstream patch, or
`expr-eval-fork <= 3.0.0`.
4. For each evaluator call site, determine:
- who controls the expression string;
- whether the surface is server-side, browser-only, internal, customer
reachable, cross-tenant, webhook reachable, or marketplace/integration
reachable;
- how the variables object is built;
- whether the variables object can contain functions, class instances,
object members, service clients, filesystem/process helpers, request
helpers, database clients, logger objects, SDK clients, tenant data, or
secrets.
5. If the repository only contains unrelated prose or an externally owned
formula service, stop with `TRIAGE.md` listing checked files, owner,
observed versions, required fixed state, and any operator action.
6. Replace vulnerable packages:
- remove original `expr-eval` unless this repository carries and verifies a
reviewed downstream patch;
- upgrade `expr-eval-fork` to `3.0.1+`;
- update imports, compatibility wrappers, lockfiles, SBOMs, generated
dependency reports, container layers, and docs.
7. Harden every evaluator context:
- build a fresh null-prototype or plain literal object from explicit
allowlisted formula variables;
- copy only primitive values and reviewed pure functions required by the
formula feature;
- block inherited properties, prototype mutation names, constructor access,
member traversal to application helpers, and object spreads from request
or tenant context objects;
- never pass service containers, request objects, ORM models, SDK clients,
module exports, filesystem helpers, process helpers, loggers, or secrets
into `evaluate()`.
8. Add safe regression tests:
- legitimate formulas still work;
- direct non-allowlisted function calls are rejected;
- nested member calls to context object methods are rejected;
- `constructor`, `prototype`, and `__proto__` style identifiers are
rejected or treated as data;
- evaluator errors do not log secrets, full request bodies, tenant data, or
dangerous expression strings;
- tests prove no process spawn, file write, file read, or network request
happens before rejection, using spies or mocks rather than real effects.
9. Add a PR body section named `CVE-2025-12735 operator actions` that states:
- package versions before and after;
- whether original `expr-eval` was removed or a reviewed downstream patch
was carried;
- which formula/evaluator surfaces were customer reachable or server-side;
- which context values were removed or allowlisted;
- whether CVE-2025-13204 was also checked;
- whether logs, secrets, tokens, or tenant credentials need review or
rotation;
- which validation commands passed.
10. Run available validation: package install, lockfile integrity, unit tests,
evaluator regression tests, dependency/security scans, lint/typecheck,
build, container build, SBOM refresh, generated docs checks, and a
non-secret local smoke test.
11. Use PR title:
`fix(sec): remediate CVE-2025-12735 in expr-eval`.
## Stop conditions
- No controlled manifest, lockfile, generated artifact, or runtime evaluator
call site uses `expr-eval` or `expr-eval-fork`.
- The repository only invokes a formula service owned by another team or SaaS
provider.
- A safe replacement would require a broad product migration outside the CVE
remediation scope.
- The fixed fork's breaking changes cannot be adopted without product owner
decisions; document containment and owner deadline in `TRIAGE.md`.
- Safe verification would require live RCE, real secrets, production formulas,
customer data, production logs, or external network callbacks.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Verification - what the reviewer looks for
- No controlled manifest, lockfile, SBOM, generated dependency report,
container layer, or deployment artifact resolves original
expr-evalwithout a reviewed patch, orexpr-eval-fork <= 3.0.0. - Every evaluator call site builds its context from explicit allowlisted data
instead of passing request, service, SDK, filesystem, process, or tenant
objects through to
evaluate(). - Regression tests prove direct function calls, nested member calls, and prototype-style property names are rejected without real process, filesystem, network, or secret access.
- The PR distinguishes package presence from reachable evaluator exposure.
- Operator notes cover server-side/customer-reachable formula surfaces, logs, secrets, tenant data, CVE-2025-13204 adjacency, and any credential rotation decision.
Output contract
- Reviewer-ready PR removing vulnerable
expr-eval/expr-eval-forkversions or replacing them with a reviewed safe parser path and refreshed artifacts. - Evaluator contexts rebuilt from explicit allowlisted primitives or reviewed pure functions, with request/service/SDK/filesystem/process objects excluded.
- Safe regression tests for non-allowlisted function calls, nested member calls, prototype-style identifiers, legitimate formulas, and secret-safe errors without real process, file, network, or secret access.
TRIAGE.mdwhen package, formula runtime, or migration ownership is outside this repository.
Watch for
- Upgrading to
expr-eval-fork 3.0.0instead of3.0.1+; the advisory marks3.0.0as affected. - Editing
package.jsonwhile a lockfile, generated dependency report, SBOM, Docker layer, or vendored bundle still resolves the vulnerable package. - Passing a sanitized expression to a still-dangerous variables object.
- Treating browser-only calculator widgets the same as server-side customer-reachable formula engines; exposure and operator work differ.
- Replacing
expr-evalwitheval,new Function, Nodevm, or a template compiler that is easier to exploit. - Logging rejected formulas, evaluator errors, variable maps, request bodies, tenant data, secrets, or generated credentials during incident review.
Related recipes
- CVE-2025-11953 React Native CLI Metro command injection
- CVE-2025-3248 Langflow validate/code RCE
- CVE intelligence intake gate
References
- GitHub Advisory Database: https://github.com/advisories/GHSA-jc85-fpwf-qm7x
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-12735
- CERT/CC VU#263614: https://www.kb.cert.org/vuls/id/263614
- Patch discussion: https://github.com/silentmatt/expr-eval/pull/288
- Fixed fork regression tests: https://github.com/jorenbroekema/expr-eval/blob/460b820ba01c5aca6c5d84a7d4f1fa5d1913c67b/test/security.js
- Adjacent NVD record: https://nvd.nist.gov/vuln/detail/CVE-2025-13204