Trigger.dev: Missing Authentication in Run Replay Action Allows Cross-Organization Task Execution (IDOR)
GHSA-pp95-gc86-jq6q · published 2 Oct 2026
How serious is it
- Severity: high.
- 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 GHSA-pp95-gc86-jq6q?
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.2
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.2 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
### Summary
The run replay `action` function at `apps/webapp/app/routes/resources.taskruns.$runParam.replay.ts` has no authentication or authorization check. While the `loader` (GET) in the same file properly calls `requireUser(request)` and scopes queries to the user's organizations, the `action` (POST) at line 166 does neither — allowing any authenticated user to replay task runs from any organization by knowing the run's `friendlyId`.
### Details
**Vulnerable file:** `apps/webapp/app/routes/resources.taskruns.$runParam.replay.ts`
**The `loader` (line 28-29) — properly authenticated:**
```typescript
export async function loader({ request, params }: LoaderFunctionArgs) {
const user = await requireUser(request); // ✓ Auth check
const userId = user.id;
// ... queries scoped to user's orgs
}
```
**The `action` (line 166-193) — NO authentication:**
```typescript
export const action: ActionFunction = async ({ request, params }) => {
const { runParam } = ParamSchema.parse(params);
// ✗ NO requireUser() call
// ✗ NO requireUserId() call
// ✗ NO org membership check
const taskRun = await prisma.taskRun.findFirst({
where: {
friendlyId: runParam, // Queries ANY run, no org scoping
},
include: {
runtimeEnvironment: { select: { slug: true } },
project: { include: { organization: true } },
},
});
// ... proceeds to replay the run in the victim's environment
const replayRunService = new ReplayTaskRunService();
```
The Prisma query at line 177 fetches the run by `friendlyId` only — no `userId` or organization filter. The `ReplayTaskRunService` then creates a new task run in the victim's environment, executing with the victim's environment variables and secrets.
**Same bug class exists in:** `apps/webapp/app/routes/resources.batches.$batchId.check-completion.ts` (line 17) — the `action` has zero authentication, allowing any user to trigger batch completion for any batch ID.
### PoC
**Run replay IDOR:**
```bash
# Any authenticated user can replay any org's task run
POST /resources/taskruns/run_abc123def/replay
Cookie: <any-valid-session>
Content-Type: application/x-www-form-urlencoded
environmentId=<victim-env-id>&failedRedirect=/
```
The `friendlyId` values (e.g., `run_abc123def`) are short, incrementing strings that can be enumerated.
**Batch completion (same bug class):**
```bash
# Any authenticated user can trigger batch completion for any batch
POST /resources/batches/<batchId>/check-completion
Cookie: <any-valid-session>
Content-Type: application/x-www-form-urlencoded
redirectUrl=/
```
### Impact
- **Cross-organization task execution:** An attacker can replay task runs belonging to other organizations, executing tasks in the victim's environment with the victim's secrets and API keys
- **Secret exposure:** Replayed tasks run with the victim organization's environment variables, which may contain database credentials, API keys, and other secrets
- **Resource consumption:** Attacker consumes the victim's compute quota by replaying their tasks
- **Data integrity:** The batch completion endpoint can prematurely resume parent tasks waiting for batch results, causing data integrity issues
- **Low attack complexity:** `friendlyId` values are short, predictable strings — enumeration is feasible
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-pp95-gc86-jq6q
- github.com/triggerdotdev/trigger.dev/pull/4199
- github.com/triggerdotdev/trigger.dev/commit/34b1a181c2a1d33a53ebab88f84b05f81fea4254
- github.com/triggerdotdev/trigger.dev
- github.com/triggerdotdev/trigger.dev/releases/tag/v4.5.2
Merged from OSV. Last updated 25 Oct 2026. All vulnerabilities · RSS · JSON