Skip to content

fix(supervisor): authorize the dequeue route and reject absent tokens in enforce mode - #4898

Closed
AUTHENSOR wants to merge 1 commit into
triggerdotdev:mainfrom
AUTHENSOR:redthread/fix-workload-server-authz
Closed

fix(supervisor): authorize the dequeue route and reject absent tokens in enforce mode#4898
AUTHENSOR wants to merge 1 commit into
triggerdotdev:mainfrom
AUTHENSOR:redthread/fix-workload-server-authz

Conversation

@AUTHENSOR

Copy link
Copy Markdown

Summary

The supervisor's workload server is the trust boundary between tenant task code and the run data plane: runners connect to it to dequeue and start run attempts, and it serves the run payload plus the environment's env vars. While auditing a self-hosted (k8s/docker) deployment, three gaps line up so that anything network-adjacent to the workload server can pull runs and their secrets from other deployments without any credentials:

  1. WORKLOAD_TOKEN_ENFORCEMENT defaults to disabled, and the helm chart doesn't expose an override — so stock self-hosted deployments ship with no workload-token requirement at all.
  2. Even with WORKLOAD_TOKEN_ENFORCEMENT=enforce, a request with no token header at all passes: authorizeWorkloadRequest only rejected jwt_invalid (a present-but-invalid token); token_absent was accepted, so simply omitting the header bypassed enforcement entirely.
  3. The dequeue route (GET /api/v1/workload-actions/deployments/:deploymentId/dequeue) never called authorizeWorkloadRequest at all — unguarded in every mode.

With those three in place, an unauthenticated attempts/start or dequeue (knowing only run + snapshot friendly IDs) returns the run payload and the environment's env vars. From a PoC harness against a stock-config supervisor with a stubbed worker client:

[poc] A(default): HTTP 200 body.envVars={"SECRET_API_KEY":"prod-secret-value"}
[poc] A(default): forwarded environmentId=undefined (undefined = unscoped)
[poc] A(enforce): HTTP 200 forwarded environmentId=undefined — absent header BYPASSES enforcement
[poc] B: HTTP 200 forwarded=true (no deployment token supplied)

Because the request was never verified, the supervisor forwards no environment id upstream, so the platform serves the env vars unscoped rather than scoped to the caller's environment.

What this PR changes

Two changes in apps/supervisor/src/workloadServer/index.ts — the code-level guard only:

  • The dequeue route now calls authorizeWorkloadRequest and answers 401 when it fails, like the other workload-action routes.
  • In enforce mode, token_absent is rejected alongside jwt_invalid. Enforce mode means the operator has explicitly opted in, so failing requests with no token header is what "enforce" promises. The doc comment on authorizeWorkloadRequest is updated to match.

Behavior in the default (unenforced) mode is unchanged — this PR does not turn enforcement on.

Deliberately not changed (flagging for maintainers)

The remaining exposure is a deployment-default / product-policy question rather than a code bug, so I didn't change it unilaterally:

  • Enforcement still defaults to disabled, and the helm chart / docker compose still don't expose a convenient opt-in. Flipping the default (or adding a chart value) is a compatibility decision for pre-token runners that maintainers should make.
  • Legacy bare deployment ids (legacy_bare, a bare friendlyId from a pre-upgrade runner) still pass in enforce mode, for the same upgrade-compatibility reason.
  • The webapp's created-at gate backstop (rejecting tokens minted before a cutoff) is likewise a policy default that is currently off.

Happy to follow up with a helm value for WORKLOAD_TOKEN_ENFORCEMENT if you want one.

Testing

  • PoC (vitest against the real WorkloadServer with a stubbed worker client, no real credentials) shows both routes answering 200 with env vars before the fix, and 401 in enforce mode after it; the default-mode path is unchanged.
  • oxlint on the changed file: clean.

… in enforce mode

The workload server's dequeue route never called authorizeWorkloadRequest,
and enforce mode only rejected present-but-invalid deployment tokens
(jwt_invalid), letting requests with no token header at all (token_absent)
through. Guard the dequeue route like the other workload-action routes and
fail token_absent when WORKLOAD_TOKEN_ENFORCEMENT=enforce.
@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f274d9b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Hi @AUTHENSOR, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions Bot closed this Sep 7, 2026
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 1c588d61-e18e-4149-b023-bc51cd6852a3

📥 Commits

Reviewing files that changed from the base of the PR and between 0a23814 and f274d9b.

📒 Files selected for processing (1)
  • apps/supervisor/src/workloadServer/index.ts

Walkthrough

The workload server now rejects absent or invalid tokens when token enforcement is enabled. The deployment dequeue route now uses authorizeWorkloadRequest and returns 401 when authorization fails. The related authorization comment now documents both rejection cases.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

1 security issue not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

const result = await verifyDeploymentIdHeader(this.deploymentIdFromRequest(req), "http");

if (result.outcome === "jwt_invalid" && workloadTokenEnforced) {
if (workloadTokenEnforced && (result.outcome === "jwt_invalid" || result.outcome === "token_absent")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Enforce-mode test contradicts new behavior

The existing enforce-mode test expects an absent token to return 200. authorizeWorkloadRequest now returns 401, so the test fails.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

const result = await verifyDeploymentIdHeader(this.deploymentIdFromRequest(req), "http");

if (result.outcome === "jwt_invalid" && workloadTokenEnforced) {
if (workloadTokenEnforced && (result.outcome === "jwt_invalid" || result.outcome === "token_absent")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Server fix lacks release note

This user-visible server fix adds 401 responses in enforce mode. Repository rules require a .server-changes/ entry, but none exists.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@AUTHENSOR

Copy link
Copy Markdown
Author

Closed by the vouch bot — understood, I hadn't been vouched. The PR contains a reproducible runner-boundary authorization fix (unguarded dequeue route + absent-token bypass of WORKLOAD_TOKEN_ENFORCEMENT=enforce in apps/supervisor); I'm happy to open a vouch request issue, re-open this after vouching, or share details privately with a maintainer if that's preferred for the security-relevant parts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant