Public mode

No access to your tenant or devices. Every item links to its source. What this means

Sources need attention Customize Public modeDiscuss ChangeIntel on Discord

Trigger.dev before 4.5.2 Unauthorized Environment Access via Run Replay

CVSS 4.0 8.4 HIGHCVSS 3.1 8.5 HIGHEUVD CVSS 4.0 8.4 CVSS 4.0 · [email protected] · Secondary 8.4 HIGHCVSS 3.1 · [email protected] · Secondary 8.5 HIGHCVSS_V3 Publisher rating HIGHFixed by trigger.dev 4.5.2KEV status unknown

cve-program · CVE-2026-85651

Published

Trigger.dev versions before 4.5.2 fail to validate environment membership during run replay operations, allowing authenticated attackers to inject task runs into arbitrary environments. Attackers can replay their own runs into other organizations' or projects' environments to consume victim resources and pollute run history.

Read the publisher's advisory

euvd · EUVD-2026-71115

Published

Trigger.dev versions before 4.5.2 fail to validate environment membership during run replay operations, allowing authenticated attackers to inject task runs into arbitrary environments. Attackers can replay their own runs into other organizations' or projects' environments to consume victim resources and pollute run history.

Read the publisher's advisory

nvd · CVE-2026-85651

Published

Trigger.dev versions before 4.5.2 fail to validate environment membership during run replay operations, allowing authenticated attackers to inject task runs into arbitrary environments. Attackers can replay their own runs into other organizations' or projects' environments to consume victim resources and pollute run history.

Read the publisher's advisory

osv · GHSA-qxpp-qjg8-x4jv

Published

### Summary The dashboard replay action authorizes the source run (it must belong to the caller's org), but the target environment for the replayed run is taken verbatim from the request body and is never checked for org or project membership. The environment lookup used by the replay path filters by id only. As a result, an authenticated user can replay one of their own runs into another organization's or project's environment, creating a task run there that consumes the victim tenant's queue and compute and pollutes their run history. ### Details The replay action member-scopes the source run correctly (apps/webapp/app/routes/resources.taskruns.$runParam.replay.ts, the findFirst on taskRun filtered by `project.organization.members.some.userId`), but passes the target environment straight from the submitted form, resources.taskruns.$runParam.replay.ts:344-346: ```js const replayRunService = new ReplayTaskRunService(); const newRun = await replayRunService.call(taskRun, { environmentId: submission.value.environment, // attacker-controlled, unvalidated payload: submission.value.payload, ... }); ``` `submission.value.environment` comes from ReplayRunData (apps/webapp/app/v3/replayTask.ts: `environment: z.string().optional()`), so it is fully client-controlled. ReplayTaskRunService resolves it with no ownership check, apps/webapp/app/v3/services/replayTaskRun.server.ts:26-28: ```js const authenticatedEnvironment = await findEnvironmentById( overrideOptions.environmentId ?? existingTaskRun.runtimeEnvironmentId ); ``` findEnvironmentById, apps/webapp/app/models/runtimeEnvironment.server.ts:197-211: ```js export async function findEnvironmentById(id) { const environment = await $replica.runtimeEnvironment.findFirst({ where: { id }, // no membership / org / project filter include: authIncludeWithParent, }); if (!environment || environment.project.deletedAt !== null) return null; return toAuthenticated(environment); } ``` The resolved environment is then handed to TriggerTaskService.call (apps/webapp/app/v3/services/triggerTask.server.ts), which trusts the passed authenticatedEnvironment and performs no further authorization. The replay loader does constrain the environment picker to the run's own project (replay.ts around 178-184), but the action does not re-impose that constraint, so the server-side control is missing (UI-gated only). ### PoC As an authenticated user who owns a run in their own org (run param runParam), and who knows a target environment id belonging to another org or project (a CUID, obtained or guessed): ```http POST /resources/taskruns/<own runParam>/replay Content-Type: application/x-www-form-urlencoded environment=<environment id of the victim org/project>&failedRedirect=/... ``` The replay resolves the victim environment with no membership check and calls TriggerTaskService against it, creating a run in the victim tenant. Live-validated: a Postgres database was seeded with two tenants (orgA with env_A, orgB with env_B_victim) and the verbatim findEnvironmentById lookup (findFirst joining the environment to its project, `WHERE id = $1`, the exact query the replay path runs) was executed with the victim env id as an orgA attacker. Captured: ``` [002 replay findEnvironmentById] attacker(orgA) supplied env_B_victim -> {"id":"env_B_victim","organization_id":"orgB","project_id":"proj_B","deleted_at":null} CROSS-TENANT: CONFIRMED (resolved another org's env with no membership check -> replay would run there) ``` The lookup returned another organization's environment with no membership filter. That the replay action passes the client-supplied environmentId straight into this lookup (and TriggerTaskService trusts the returned env) is verified at source. ### Impact An authenticated user can create task runs in another tenant's environment (including production), consuming that tenant's queue concurrency and compute and inserting entries into their run history. Practical exploitation requires knowing a target environment id (not enumerable) and, for the injected run to actually execute rather than error, a task identifier that exists in the target environment; this bounds reliability but not the unauthorized cross-tenant write itself. ### Remediation In the replay action (or in ReplayTaskRunService), require the resolved target environment to belong to the source run's project/organization, for example assert `environment.projectId === existingTaskRun.projectId`, or re-validate the supplied environment id against the caller's membership (findEnvironmentBySlug with the validated projectId, or a members.some.userId filter), mirroring the constraint the loader already applies to the picker.

Read the publisher's advisory

Affected versions, risk and source history

cve-program · CVE-2026-85651

Published

trigger.dev

Vendor product

Publisher's version information

Shown as published. These rules are not interpreted as NuGet package version ranges.

{
                    "vendor": "triggerdotdev",
                    "product": "trigger.dev",
                    "defaultStatus": "unaffected",
                    "versions": [
                        {
                            "version": "0",
                            "lessThan": "4.5.2",
                            "status": "affected",
                            "versionType": "semver"
                        }
                    ]
                }

Original source record · Cite this exact observation · Complete original publisher JSON

euvd · EUVD-2026-71115

Published

EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.

Original publisher date fields

datePublished: Sep 4, 2026, 2:32:17 PM

dateUpdated: Sep 10, 2026, 3:08:30 PM

No normalized affected-package data is projected for this source revision. The original publisher record may contain additional product and version evidence; this does not establish that a package is unaffected.

Original source record · Cite this exact observation · Complete original publisher JSON

nvd · CVE-2026-85651

Published

NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.

Source analysis status: Deferred

Weakness classifications: CWE-862

Original publisher date fields

published: 2026-09-04T15:17:43.347

lastModified: 2026-09-23T17:17:43.317

No normalized affected-package data is projected for this source revision. The original publisher record may contain additional product and version evidence; this does not establish that a package is unaffected.

Original source record · Cite this exact observation · Complete original publisher JSON

osv · GHSA-qxpp-qjg8-x4jv

Published

trigger.dev

npm

SEMVER · introduced 0 → fixed 4.5.2

Original source record · Cite this exact observation · Complete original publisher JSON

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 12 Nov 17:32 UTC · 274 of 275 readable · 272 fully read · documentation 469/469 current