Trigger.dev: Cross-environment deployment cancel
Summary
Trigger.dev isolates each project into multiple environments (dev, staging, prod, and per-PR preview branches), each with its own secret API key — the environment is a trust boundary (a dev/preview/CI key is lower-trust than a prod key). Most API routes enforce this by scoping resource lookups to the authenticated key's environment (where: { friendlyId, runtimeEnvironmentId: auth.environment.id }).
The deployment cancel path does not. DeploymentService.getDeployment() scopes the lookup by projectId only — never environmentId — so a secret key for any environment in a project can cancel a deployment belonging to any other environment of the same project, including production. The deployment GET route, by contrast, is env-scoped — so the same key that is 404'd when trying to read a prod deployment can nonetheless cancel it. That asymmetry is the bug.
Affected
apps/webapp, HEAD 5d99457 (current main). Affects self-hosted and cloud.
Root cause
apps/webapp/app/routes/api.v1.deployments.$deploymentId.cancel.ts authenticates to an environment and calls deploymentService.cancelDeployment(authenticatedEnv, deploymentId, ...).
apps/webapp/app/v3/services/deployment.server.ts:
public cancelDeployment(authenticatedEnv: Pick<AuthenticatedEnvironment,"projectId">, friendlyId, ...) {
return this.getDeployment(authenticatedEnv.projectId, friendlyId) // projectId only
.andThen(validateDeployment) // rejects only FINAL statuses
.andThen(cancelDeployment); // updateMany -> status CANCELED
}
private getDeployment(projectId: string, friendlyId: string) {
return this._prisma.workerDeployment.findFirst({
where: { friendlyId, projectId }, // <-- NO environmentId filter
});
}
cancelDeployment accepts authenticatedEnv but its type is literally Pick<AuthenticatedEnvironment,"projectId"> — it discards the environment identity. validateDeployment blocks only FINAL_DEPLOYMENT_STATUSES, so any in-progress deployment (PENDING/INSTALLING/BUILDING/DEPLOYING) is cancellable.
Contrast — the correctly env-scoped sibling api.v1.deployments.$deploymentId.ts (GET):
const deployment = await prisma.workerDeployment.findFirst({
where: { friendlyId: deploymentId, environmentId: authenticatedEnv.id }, // env-scoped
});
Reads are env-scoped; the cancel mutation is not. The same getDeployment(authenticatedEnv.projectId, …) helper also backs the deployment progress methods (deployment.server.ts:172,329), so the projectId-only scope is a small class.
Runtime PoC (proven on the self-host stack)
Seeded one project with a prod env (key tr_prod_…) and a dev env (key tr_dev_…) and one WorkerDeployment (deployment_pocvictim, status DEPLOYING) in the prod env. As the dev key:
status BEFORE : DEPLOYING
GET /api/v1/deployments/deployment_pocvictim (dev key) -> 404 (env-scoped read DENIES it)
POST /api/v1/deployments/deployment_pocvictim/cancel (dev key) -> 204
status AFTER : CANCELED (prod deploy canceled by the dev key)
CONTROL: same cancel with a DIFFERENT project's key -> 404 (projectId scope blocks cross-project)
The dev key cannot read the prod deployment (404) yet cancels it (204 → CANCELED); a different project's key is correctly 404'd — so the gap is precisely cross-environment within a project.
Affected software
Click a technology to see all vulnerabilities affecting it.
| Platform | Package | Vulnerable versions | Fixed in |
|---|---|---|---|
| npm package | trigger.dev | < 4.5.6 | 4.5.6 |
References
- https://github.com/triggerdotdev/trigger.dev/security/advisories/GHSA-4672-hwv6-gq62
- https://github.com/triggerdotdev/trigger.dev/pull/4316
- https://github.com/triggerdotdev/trigger.dev/commit/6997aeb05e27d2db47f9eda01fdc8a17c81a1ae0
- https://github.com/triggerdotdev/trigger.dev
- https://github.com/triggerdotdev/trigger.dev/releases/tag/v4.5.6
- CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L- Weakness (CWE)
CWE-639- Platform
- npm
- Package
trigger.dev- Disclosed
- 02.10.2026
- Updated
- 11.10.2026 10:22
Sources and licenses
OSV / GitHub Advisory Database - GHSA-4672-hwv6-gq62 - CC BY 4.0
Vulnerability history: trigger.dev
All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.
- Total entries
- 10
- First → latest
- 10.2026 10.2026
- Without a fix
- 0
- Exploited in attacks
- 0
Severity breakdown
- Critical 1
- High 5
- Medium 4
Disclosures per year
- 2026: 10
-
Trigger.dev: Cross-environment deployment cancel this entry
Know which vulnerabilities affect your application
With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.