A CI token that can deploy to production while it is running unit tests is a misconfiguration. The token does not become dangerous only when it leaks; it is dangerous the moment it exists with more authority than the stage holding it requires. The per-Worker access scoping announced by Cloudflare on 15 September 2026 removes the previous excuse for over-provisioning: the platform now lets you assign narrower Developer Platform roles to CI tokens, agents, and teammates scoped to individual Workers rather than the whole account. (Cloudflare blog)
This article treats that capability as an enabling mechanism, not a solution by itself. The hard part is not clicking the right button in the dashboard. The hard part is deciding, for every token your pipeline holds, exactly which permissions are necessary, and then encoding that decision as a check the pipeline can fail.
What changed and what remains on you
According to the Cloudflare announcement, you can now scope access to individual Workers and assign narrower Developer Platform roles so that teammates, CI tokens, and agents get only the access they need to debug, deploy, or monitor safely. (Cloudflare blog)
What the platform change does not do on its own:
- It does not audit your existing tokens or flag the ones that are over-provisioned.
- It does not prevent you from creating a new account-level token out of habit.
- It does not stop an autonomous agent from being granted broad access if the person creating its credential does not think carefully about scope.
- It does not tell you which token, if compromised, gives an attacker the widest blast radius.
All of those remain engineering decisions. The sections below give you a framework for making them deliberately.
Decision checklist: classify every token before you redesign anything
Run this checklist against each credential your pipeline currently holds. Classify each one before touching permissions, because redesigning a token you do not yet understand often produces a differently-wrong result.
For each token, answer these questions in order:
What pipeline stage holds this token? Name the stage concretely: lint, unit test, integration test, deploy to staging, deploy to production, post-deploy smoke test. A token shared across stages is a signal worth investigating.
What actions does the code in that stage actually invoke? List API calls, Wrangler commands, or platform operations the stage performs. Not what it could do, but what the job scripts actually call.
What does the token currently permit? Pull the token's role or permission set from your secrets manager or the platform dashboard. Compare it to the list from step 2.
Is every permitted action called? If the token permits
workers:writebut the stage only reads logs, that gap is an over-provision. Mark it.Does the token scope to a specific Worker or to the account? Account-level scope means a compromised token can touch every Worker. Worker-level scope limits the blast radius to one resource.
Classification:
- Correctly scoped: Every permission is used; scope is as narrow as the platform allows.
- Over-provisioned: One or more permissions are unused, or scope is broader than necessary.
- Unresolvable without platform changes: The permission you need does not exist at a narrower scope. Document this explicitly rather than accepting broad scope silently.
Do not skip the classification step. Tokens in the "unresolvable" category are legitimate candidates for raising with your platform team or tracking as accepted risk, but they should be conscious decisions, not invisible ones.
Worked example: a three-stage pipeline with minimum-permission tokens
Assume a pipeline with three stages: static analysis and lint, integration testing against a staging Worker, and production deploy. The Worker is named payment-processor.
This is an illustrative example. The exact permission names available to you will depend on which roles Cloudflare exposes at the time you read this; treat the permission labels here as placeholders for the narrowest available equivalent.
Stage 1: Lint and static analysis
What the stage does: Runs ESLint, TypeScript type checking, and a custom AST analysis pass. It reads source files from the repository. It does not communicate with the Cloudflare API at all.
Token needed: None. This stage should not hold a Cloudflare credential. If your current pipeline injects one here by default (for example, because a shared environment block passes it to every job), that is an over-provision to fix immediately.
Why exclude it: A static analysis job that leaks its environment has no useful credential to expose. A static analysis job that leaks an account-level deploy token is a supply-chain incident.
Stage 2: Integration test
What the stage does: Deploys a preview of payment-processor to an isolated staging environment, runs the integration test suite against it, and reads the Worker's tail logs to capture assertion failures.
Token needed: A token scoped to payment-processor only, with permissions to:
- Deploy (write) to the staging environment of that specific Worker
- Read tail logs for that Worker
Explicitly excluded permissions and the justification for each exclusion:
| Permission | Why excluded |
|---|---|
| Deploy to production | Integration tests must not be able to promote themselves |
| Account-level Worker list | The test only needs one Worker; enumeration is unnecessary |
| KV namespace write (production) | Tests should use a seeded test namespace; production KV must be unreachable |
| DNS or route modification | Routing changes are a deploy-stage concern, not a test concern |
| Delete Worker | No test workflow should be able to destroy a Worker |
The integration token's blast radius, if compromised: an attacker can deploy arbitrary code to the staging instance of payment-processor and read its logs. They cannot touch production, other Workers, or account-level resources. That is an acceptable and bounded risk.
Stage 3: Production deploy
What the stage does: Runs wrangler deploy targeting the production environment of payment-processor after all upstream gates pass.
Token needed: A token scoped to payment-processor only, with permission to deploy to the production environment of that Worker.
Explicitly excluded permissions and the justification for each exclusion:
| Permission | Why excluded |
|---|---|
| Read tail logs | The deploy job does not need runtime observation; that belongs to observability tooling with its own credential |
| Access to other Workers | A deploy credential for payment-processor must not be reused for auth-service or any other Worker |
| Account settings | Production deploy does not require account administration |
| Delete Worker | Deletion is a break-glass operation, not a deploy operation |
The production deploy token's blast radius, if compromised: an attacker can deploy arbitrary code to payment-processor in production. That is a meaningful risk and should drive complementary controls: short token TTL, deployment confirmation hooks, and post-deploy integrity checks. The blast radius is still scoped to one Worker, not the whole account.
Summary: before and after
| Stage | Before (typical) | After |
|---|---|---|
| Lint | Account-level token (injected by default) | No credential |
| Integration test | Account-level deploy token | Worker-scoped token, staging + log-read only |
| Production deploy | Same account-level token as integration | Worker-scoped token, production deploy only |
The "before" column describes a pattern pipelines commonly fall into when token creation is done once during initial setup and never revisited. It is not the only way pipelines go wrong, but it is a frequent one.
Learning exercise: blast-radius mapping
This exercise produces a concrete answer to one question: which token, if compromised right now, would give an attacker the most capability?
Step 1: Build a permission matrix.
Create a table with your pipeline tokens as columns and meaningful attacker capabilities as rows. Capabilities to include:
- Can deploy to production Workers
- Can read production secrets or environment variables
- Can enumerate all Workers on the account
- Can modify DNS or routing
- Can delete Workers
- Can access KV or Durable Object data in production
- Can create or modify other tokens (token management)
Fill each cell with Yes, No, or Unknown. Treat Unknown the same as Yes for blast-radius purposes until you confirm otherwise.
Step 2: Score each token.
Count the Yes and Unknown cells per token column. The token with the highest count is your current highest blast-radius credential. If it is the token your integration test job holds, that is the finding you act on first.
Step 3: Redesign the worst offender.
For the token with the highest score, go back to the decision checklist. For every Yes or Unknown cell, ask: does the stage that holds this token actually invoke this capability? If not, it is an over-provision. If you cannot remove the permission because the platform does not offer a narrower scope, document it in the Unresolvable category and evaluate whether that stage should exist in its current form.
Step 4: Encode the constraint as a pipeline check.
Once you have redesigned the token, write a check that fails the pipeline if the token's scope has drifted. The mechanism depends on your platform, but the pattern is consistent: before the stage that uses the token runs its primary job, a preflight step calls the platform's token introspection or permissions API and asserts that the returned permission set matches the expected minimum. If the token has been rotated to a broader credential by accident or by an unauthorized change, the pipeline fails before any deployment occurs.
This is the core framing of credential scoping as a verification gate. You are not just configuring least privilege once; you are continuously asserting it as an invariant. A token that was correctly scoped last week can be replaced with an over-provisioned one today if someone regenerates it carelessly. The preflight check catches that regression at the same place and in the same way that a failing unit test catches a logic regression.
Consider the difference concretely. An attacker who compromises a correctly scoped token during a lint stage gets a credential with no platform access. An attacker who compromises that same token after an accidental rotation to account-level scope gets the keys to every Worker on your account. The code in the lint stage did not change. The invariant assertion is the only thing standing between those two outcomes.
Handling autonomous agents
Agents introduce a variation worth calling out separately. An autonomous agent that can trigger deploys, read logs, and call external APIs on behalf of your pipeline is a principal with a credential, exactly like a CI token. The same checklist applies.
The additional concern with agents is that their action space is often less predictable than a scripted CI job. A scripted job calls a fixed set of commands. An agent may decide at runtime to invoke a capability you did not anticipate. This makes the preflight permission assertion more important, not less: you want to know before the agent runs that it cannot exceed its intended scope, because you cannot enumerate every action it might take.
For agents, consider adding a post-run audit step that logs every platform API call made during the agent's execution and flags any call that was not in the expected set. This does not prevent an agent from misusing a permission it holds, but it surfaces unexpected capability use for review before the next run.
What to do before the platform supports your ideal scope
Some permission boundaries you want may not yet exist in the platform. If you need a credential that can read tail logs but cannot write to KV, and the platform only offers those as a bundle, you have a few options:
- Accept the broader scope, classify it as Unresolvable, and document the accepted risk explicitly with a review date.
- Split the stage into two jobs where possible, so the KV-write job has a short TTL token that expires before the log-read job begins.
- Use a sidecar process with a separate credential for the capability you want to isolate, rather than giving one token both permissions.
None of these options are perfect. The point is to make the tradeoff visible and revisited rather than invisible and permanent.
If you want to put a verification gate on this kind of invariant inside a structured pipeline, OpenThunder Dev is worth a look.