
PEACH
Uma estrutura de isolamento de inquilino
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.
apps/webapp, HEAD 5d99457 (current main). Affects self-hosted and cloud.
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.
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.
Origem: NVD
Avaliação de vulnerabilidade gratuita
Avalie suas práticas de segurança na nuvem em 9 domínios de segurança para comparar seu nível de risco e identificar lacunas em suas defesas.
Marque uma demonstração personalizada
"A melhor experiência do usuário que eu já vi, fornece visibilidade total para cargas de trabalho na nuvem."
"A Wiz fornece um único painel de vidro para ver o que está acontecendo em nossos ambientes de nuvem."
"Sabemos que se a Wiz identifica algo como crítico, na verdade é."