Repository navigation
Remove the legacy proxy token - #380
Merged
Brooooooklyn merged 8 commits intoOct 7, 2026
Merged
Brooooooklyn merged 8 commits into
Brooooooklyn merged 8 commits into
Conversation
Brooooooklyn
added this pull request to stack #381
October 6, 2026 21:33
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://security-1d-remove-legacy-proxy-token-void-cloud.voidzero-docs.workers.dev (commit 2d57273)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
cpojer
reviewed
Oct 7, 2026
cpojer
left a comment
Member
There was a problem hiding this comment.
- I would expect the removal to remove code, not add 2x of the removals.
- Is it relevant to add this to the docs at all or can we remove the additions to the docs?
Brooooooklyn
force-pushed
the
security/1d-remove-legacy-proxy-token
branch
from
October 7, 2026 02:40
903cbc3 to
44a452f
Compare
Rollback, cutover replay and the queue token backfill no longer derive a token from JWT_SECRET when the target Worker has no __VOID_PROXY_TOKEN binding. Such a Worker never accepted that value, so its cron and queue copies now carry no token, a warning names the Worker and asks for a redeploy, and the backfill counts the entry as skipped. The backfill no longer takes a jwtSecret option. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The resolve-worker, resolve-resource and verify-prerender-build routes now require x-void-proxy-internal and ignore x-void-internal, so a tenant project token no longer authenticates them and they never read the token floor. The proxy stops sending the project token on those calls. /internal/revalidate still checks the forwarded project token. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tenant tokens are now only v2.<gen>.<mac> with gen >= 1. The accept rule is a valid MAC and a generation of at least max(floor, 1), so a missing or zero floor still accepts every v2 token. Deriving generation 0 throws, and a token in the original 43-character form is rejected before any MAC or KV work. The proxy sends nothing for a project with no issued generation: dispatch logs a warning and returns null, so authorized callers fall back to the REST path as for an old Worker. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The upgrade guide now tells operators to rotate every project's original credentials before upgrading, rotate once more right after, and how to recover when they upgraded first. The CLI reference links to it. The maintainer runbook covers the hosted release steps and why the API must not be rolled back alone below the release that checks the proxy-only metadata key. The proxy README describes only v2 tokens and the empty send for a project with no issued generation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ments Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The upgrade guide no longer asks operators to rotate before and after upgrading. It says the platform moves each project off its original credentials by itself, what fails until a project's turn comes, and that --plan shows progress. The hosted runbook adds the gate for the release that removes the legacy token: --plan must show 0 legacy, 0 pending and 0 failed, since a project leaves legacy as soon as its rotation starts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Static projects can keep earlier Worker deployments for rollback, so the scheduled run rotates them like any other deployed project. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Brooooooklyn
force-pushed
the
security/1d-remove-legacy-proxy-token
branch
from
October 7, 2026 05:13
44a452f to
2d57273
Compare
Member
Author
|
Folded into #379, which now ships rotation and legacy token removal in one release. GitHub marked this PR merged because its commits are now in its base branch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every project now has rotatable
v2.<gen>.<mac>proxy tokens and automatic rotation after upgrade (rotate-proxy-tokens --planshows progress). This PR stops accepting and sending the original token, the plain HMAC of the project id underJWT_SECRET. That token could never be revoked, and it was signed with the same key that signs login JWTs and OAuth state.Operators have no step to run before upgrading and no in-between release to install first: they upgrade, and the scheduled rotation moves any project still on the original token.
It also removes the fallback that let a tenant project token authenticate the proxy-only metadata routes. Those routes now take only the proxy's own
x-void-proxy-internalkey.Changes
platform/packages/api/src/proxy-token.tsisAcceptedGenerationis nowgen >= max(floor, 1), so a missing or zero floor still accepts every v2 token.sendGenerations(0)is empty.LEGACY_PROXY_TOKEN_STATEis renamed toNO_PROXY_TOKEN_FLOOR.platform/packages/api/src/internal-proxy-auth.tsresolve-worker,resolve-resourceandverify-prerender-buildrequirex-void-proxy-internaland ignorex-void-internal./internal/revalidatestill checks the forwarded project token against the floor.platform/packages/proxy/src/dispatch.ts,resolve.ts,proxy-token.tsx-void-internalheader is no longer sent on metadata calls.null, so callers fall back as they do for a Worker without the/__voidhandler (REST where the route has one).platform/packages/api/src/routes/projects.ts(rollback),deploy/recovery.ts(cutover replay),admin/backfill-queue-tokens.ts,operator/system-operations.tsjwtSecretoption.platform/packages/api/src/id.ts,provisioning/cloudflare-api.ts,proxy-token-rotation.ts(generation 0 now means no token has been issued; the legacy token is never accepted).docs/guide/platform/installation/maintenance.md: upgrade note, replacing the steps to rotate before upgrading. Rotation runs by itself after the upgrade, AI, email, ISR revalidation, prerendering and remote D1/KV/R2 can fail for a project until its turn, and--planshows progress. Redeploying fixes a project right away.docs/reference/cli/platform-operations.md: link to that note.platform/meta/operations.md: next to the release order, the gate (0 legacy, 0 pending, 0 failed), whylegacy: 0alone is not enough, and the--all --yesstep after a rollback below Rotate project proxy tokens when access changes #379; the note that the proxy and API no longer accept the legacy token; and the API-only rollback caveat. The__AI_TOKENquery now lives in Rotate project proxy tokens when access changes #379.platform/packages/api/README.md,platform/packages/proxy/README.md: v2-only tokens, and an empty send when no generation has been issued.api-internal-project-token,api-projects,api-revalidate,deployment-recovery,operator-operations,proxy-token-rotation), API unit (backfill-queue-tokens,proxy-token), and proxy unit (d1,dispatch,email,email-custom-domain,kv,proxy,r2,resolve).Decisions
rotate-proxy-tokens --project <id> --yesfixes it sooner, and the docs give both steps.__VOID_PROXY_TOKENbinding never accepted the derived value, so writing one only produced 401s later. These paths now leave the token empty, warn, and ask for a redeploy. We do not refuse the rollback.__AI_TOKEN(deployed before the binding rename) cannot be rotated. The runbook gives a query to list the active ones so each is redeployed before Rotate project proxy tokens when access changes #379 reaches staging and production. Self-hosted installs cannot have them. We added no tooling to patch or drop them.x-void-proxy-internal, while the proxy is on this release breaks metadata calls until both match. A self-hosted upgrade from such a release sees the same failure for the few seconds before the new proxy is live. We documented this and added no version guard, because the window is short and a guard would add friction to every upgrade.JWT_SECRET.Left as is on purpose:
Rollout
Merge gate:
rotate-proxy-tokens --planon production shows 0 legacy, 0 pending and 0 failed. Staging is the canary and gets there first; it deploys on merge, so confirm it still shows the same.legacy: 0alone is not enough: a project leaves it when its rotation starts or a deploy moves it to generation 1, while its older Workers still hold the legacy token until the rotation finishes. If either environment was rolled back below Rotate project proxy tokens when access changes #379 after it shipped, runrotate-proxy-tokens --all --yesthere first:--plancannot see a Worker redeployed with the legacy token during the rollback.Hosted release order:
This does not wait for a published #379 release. The
__AI_TOKENredeploys are done before #379 reaches each environment, so they are not part of this gate.Self-hosted operators upgrade straight to this release; rotation runs by itself, and
--planshows progress (see the upgrade note indocs/guide/platform/installation/maintenance.md). A project that errors before its turn can be redeployed to fix it right away.Do not roll back the API alone below the release that checks
x-void-proxy-internalwhile the proxy runs this release.Testing
vp run checkvp run test --base security/1c-proxy-token-rotationvp test runvp lintvp fmt --check🤖 Generated with Claude Code