CVE-2026-73654: @trigger.dev/core Prototype Pollution via Run Metadata Operations
A low-privilege API key holder can pollute Object.prototype in the shared Trigger.dev webapp process with a single HTTP request, crashing the server for all tenants and breaking other tenants' worker…

The problem
The run-metadata update endpoint (PUT /api/v1/runs/:runId/metadata) accepts a JSON array of operations. Each operation has a key field that is passed directly into new JSONHeroPath(operation.key).set(newMetadata, value) in packages/core/src/v3/runMetadata/operations.ts with no validation.
@jsonhero/path@^1.0.21 treats __proto__ as an ordinary path segment, so a key like $.__proto__.polluted writes to Object.prototype in the Node.js process. Because the webapp is multi-tenant and shared, every subsequent plain-object lookup inherits the injected property, corrupting Prisma query builders, breaking other tenants' worker authentication, and crashing the process via an uncaughtException in prom-client.
One request from any normal environment API key (tr_dev_...) is enough.
Proof of concept
A working proof-of-concept for CVE-2026-73654 in @trigger.dev/core, with the exact payload below.
curl -X PUT "http://localhost:8030/api/v1/runs/run_cmqr2bsyo00013js2twwhdsfu/metadata" \
-H "Authorization: Bearer tr_dev_<env_key>" \
-H "Content-Type: application/json" \
--data '{"operations":[{"type":"set","key":"$.__proto__.polluted","value":"PWNED"}]}'The sink is in applyMetadataOperations() (operations.ts:22-23): new JSONHeroPath(operation.key).set(newMetadata, operation.value). The request schema types key as a plain string with no allowlist or blocklist, so $.__proto__.polluted reaches @jsonhero/path's segment walker unchecked.
Because @jsonhero/path@1.0.21 resolves __proto__ as a normal property name during traversal, the .set() call assigns onto Object.prototype rather than the local metadata object. Every plain object in the process then inherits the injected key, including Prisma query argument objects (causing Unknown argument validation errors) and prom-client label sets (causing an uncaughtException that crashes the process).
The endpoint returns HTTP 200 regardless (it wraps the Prisma error with ignoreError:true), so the attacker gets no error signal while the damage propagates process-wide. The fix, per PR #4316 (commit 6997aeb), adds a guard that rejects any operation key containing __proto__, constructor, or prototype segments before the path is built, and seeds the metadata accumulator with a null-prototype object so the assignment cannot reach Object.prototype even if the check is bypassed.
The fix
Upgrade @trigger.dev/core (and the self-hosted webapp image) to **v4.5.6** (ghcr.io/triggerdotdev/trigger.dev:v4.5.6). The patch (PR #4316, commit 6997aeb) adds a blocklist rejecting __proto__, constructor, and prototype in any operation key before JSONHeroPath is constructed, and initialises the metadata accumulator with Object.create(null) so prototype-chain writes are impossible.
If an immediate upgrade is not possible, reject or strip those key segments at your API gateway or reverse proxy as a stopgap.
Related research
- critical · 9.1CVE-2026-53609CVE-2026-53609: ApostropheCMS Server-Side Prototype Pollution via $pullAll Leading to Authorization Bypass
- high · 7.3CVE-2026-54737CVE-2026-54737: @phun-ky/defaults-deep Prototype Pollution via Unsafe Recursive Merge
- high · 7.5CVE-2026-47219CVE-2026-47219: find-my-way Prototype Property Lookup DoS via HTTP/2 Method
- highCVE-2026-59206CVE-2026-59206: n8n Prototype Pollution via Workflow Credentials