Skip to content

Harden Comps SharedWorker mathjs evaluation against untrusted expressions - #10

Open
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1784904570-comps-worker-mathjs-hardening
Open

Harden Comps SharedWorker mathjs evaluation against untrusted expressions#10
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1784904570-comps-worker-mathjs-hardening

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 24, 2026

Copy link
Copy Markdown

Closes

Describe your changes:

The Comps ("Derived Telemetry") SharedWorker evaluated the persisted, attacker-controllable comps expression (configuration.comps.expression, forwarded verbatim by CompsTelemetryProvider) using the full mathjs evaluate(expression, scope) with no allow-list, length cap, or complexity bound. Because comps domain objects are shared through a common persistence store, an attacker who can create/edit a comps object could plant an expression that, when any other user views/embeds it, forces mathjs to allocate/compute without limit (e.g. zeros(1e9), ones(1e6,1e6), range(0,1e12), or a self-recursive function assignment) — hanging/OOM-ing the SharedWorker that is shared across all comps consumers in the victim's browser origin (client-side DoS). mathjs's parser is also code-exec-adjacent (evaluate/parse/simplify/derivative/resolve/import/createUnit).

Fix — a new securedMath.js module builds one hardened mathjs instance and is used by the worker:

  • Disables the code-exec-adjacent parser functions (import, createUnit, reviver, evaluate, parse, simplify, derivative, resolve) via math.import({...}, { override: true }), per mathjs security guidance. The trusted parse/evaluate are captured before the override so our own code can still use them while expressions cannot.
  • Allow-lists function/constant names. Anything that allocates or computes proportionally to a caller-supplied integer (zeros, ones, range, matrix, identity, resize, reshape, factorial, combinations, …) is excluded — any mathjs builtin not on the list is rejected.
  • Rejects user-defined function assignments (FunctionAssignmentNode) to block unbounded recursion.
  • Caps expression length (512 chars) and parse-tree size (100 nodes).

The worker (CompsMathWorker.js) now:

  • imports evaluate/validateExpression from securedMath.js (replacing the raw mathjs import),
  • validates the message payload shape (expression is a string, parameters is a well-formed array, telemetryForComps is an object) and validates the expression once up front in assertValidCalculationPayload(...) before any telemetry point reaches the engine.

Scope parameter names are always permitted as symbols, so existing valid expressions (e.g. a*2, min(a,b), sqrt(a)) continue to work.

before: import { evaluate } from 'mathjs';           // full function set, no bounds
after:  import { evaluate, validateExpression } from './securedMath.js';
        // port.onmessage -> assertValidCalculationPayload(telemetryForComps, parameters, expression)
        //   -> typeof/shape checks + validateExpression(expression, parameterNames)  // throws on disallowed/oversized
        //   -> calculate(...) -> secured evaluate(expression, scope)                 // parser fns disabled

All Submissions:

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • Is this a notable change that will require a special callout in the release notes? Malformed/oversized/disallowed expressions that previously "worked" (via unbounded builtins) now throw instead of evaluating.

Author Checklist

  • Changes address original issue?
  • Tests included and/or updated with changes? (src/plugins/comps/securedMathSpec.js)
  • Has this been smoke tested?
  • Have you associated this PR with a type: label?
  • Have you associated a milestone with this PR?
  • Testing instructions included in associated issue OR is this a dependency/testcase change?

Link to Devin session: https://app.devin.ai/sessions/5c7df0739b2642be841185dee2c3a53e
Requested by: @samanthataylor3


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)

…ions

The Comps SharedWorker evaluated the persisted, attacker-controllable
comps expression with the full mathjs function set and no bounds, so a
crafted expression (e.g. zeros(1e9), ones(1e6,1e6), range(0,1e12), or a
recursive function assignment) could hang/OOM the worker shared across
all comps consumers in a victim's browser origin.

Add a hardened mathjs instance (securedMath.js) that disables the
code-exec-adjacent parser functions per mathjs security guidance,
enforces a function/constant allow-list, rejects user-defined function
assignments, and caps expression length and parse-tree size. Validate
the worker message payload shape and the expression before evaluation.

Co-Authored-By: Samantha Taylor <samantha.taylor@cognition.ai>
@samanthataylor3 samanthataylor3 self-assigned this Jul 24, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant