The agent traffic problem

AI agents are rapidly becoming a mainstream way for users to interact with the web. Instead of manually browsing a site to order a pizza or buy concert tickets, a user will instruct an agent — running locally or in a distant data center — to complete the task end-to-end. These agents can act far faster than humans, executing multiple requests in the time it takes a person to make one click. As this pattern scales, web servers will face a fundamental shift: a surge in machine-driven traffic, a drop in conventional browser traffic, and new vectors for abuse.

The challenge for site operators is managing this new traffic without disrupting legitimate users. Existing security tools are mostly too coarse. Blocking a request pattern from an agent platform, for example, can inadvertently block every user of that platform, including those just trying to buy a pizza. The industry needs finer-grained controls, but they must not compromise user privacy.

Anonymous credentials (AC) offer a path forward. Under development at the IETF, ACs allow a server to enforce policies — rate limits, blocks on specific misbehaving users — without ever identifying the user or tracking them across requests. It is early-stage work, but it points toward a mechanism that can keep the web both secure and private as agentic AI grows.

Building a simple agent

To understand what agents mean for servers, it helps to build one. A minimal agent is a program that turns a natural-language prompt into concrete web actions. For example, a Worker that takes a prompt and uses an LLM to produce a plan and instructions. The LLM does not act on the plan; it only provides the sequence of steps:

export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
       const out = await env.AI.run("@cf/meta/llama-3.1-8b-instruct-fp8", {
           prompt: `I'd like to order a pepperoni pizza with extra cheese.
                    Please deliver it to Cloudflare Austin office.
                    Price should not be more than $20.`,
       });

       return new Response(out.response);
   },
} satisfies ExportedHandler<Env>;

Humans can execute such a list because they have agency — they can affect the world by, say, opening a browser. To give our agent agency, we can connect it to Cloudflare's Browser Rendering service, which binds directly into a Worker. Using the Stagehand automation framework, the agent can control a remote browser instance with Workers AI as the client:

import { Stagehand } from "@browserbasehq/stagehand";
import { endpointURLString } from "@cloudflare/playwright";
import { WorkersAIClient } from "./workersAIClient"; // wrapper to convert cloudflare AI

export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
       const stagehand = new Stagehand({
           env: "LOCAL",
           localBrowserLaunchOptions: { cdpUrl: endpointURLString(env.BROWSER) },
           llmClient: new WorkersAIClient(env.AI),
           verbose: 1,
       });
       await stagehand.init();

       const page = stagehand.page;
       await page.goto("https://mini-ai-agent.cloudflareresearch.com/llm");

       const { extraction } = await page.extract("what are the pizza available on the menu?");
       return new Response(extraction);
   },
} satisfies ExportedHandler<Env>;

Stagehand lets us target page elements with statements like page.act("Click on pepperoni pizza") and page.act("Click on Pay now"), making it straightforward to script browser interactions. But a more capable agent can run autonomously using Stagehand's agent mode, which forgoes step-by-step instructions in favor of giving the model direct control over the browser: complete the task itself, including payment if given access to a virtual credit card.

import { Stagehand } from "@browserbasehq/stagehand";
import { endpointURLString } from "@cloudflare/playwright";
import { WorkersAIClient } from "./workersAIClient";

export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
       const stagehand = new Stagehand({
           env: "LOCAL",
           localBrowserLaunchOptions: { cdpUrl: endpointURLString(env.BROWSER) },
           llmClient: new WorkersAIClient(env.AI),
           verbose: 1,
       });
       await stagehand.init();
       
       const agent = stagehand.agent();
       const result = await agent.execute(`I'd like to order a pepperoni pizza with extra cheese.
                                           Please deliver it to Cloudflare Austin office.
                                           Price should not be more than $20.`);

       return new Response(result.message);
   },
} satisfies ExportedHandler<Env>;

The example we built was scoped to Cloudflare's Austin office. That matters because the agent runs at a remote location — the Cloudflare edge — and the origin server can no longer assume a human is physically anywhere nearby. The agent has no context for "my location" unless we supply it.

Now multiply that capability. One person with an agent can fire off a handful of requests in a second from a data center, where a human browsing the same site might take 10 seconds per click. Thousands of such agents, some honest and some not, concentrated on a few source IP ranges, will change how origins have to think about traffic management.

What origins can do today

From an origin's perspective, the content looks similar whether a human or an agent drives the browser. What really changes is the network source of the traffic — and that matters because the tools for managing traffic are largely source-based:

BLOG-3027 image 3

A server typically has two basic tools for managing limited resources like bandwidth and CPU. The first is a global security policy: slowing down, CAPTCHA-ing, or temporarily blocking requests across the site, a specific resource, or classified attack patterns. This can be reactive, as in DDoS defense, or proactive, as with Waiting Room to absorb expected spikes in legitimate demand. The second is incentives, such as varying prices by location or time of day, implemented with a Cloudflare Snippet.

Both approaches work, but neither is surgical. Rate limiting a login endpoint to stop credential stuffing also punishes non-attackers. Before taking such measures, servers prefer to apply policies per user.

The question is how to identify an individual user. Classic heuristics combine IP addresses, User-Agent strings, account data when available, and other fingerprints. Cloudflare has used such signals for per-user rate limiting, but fingerprinting is inequitable. Mobile users struggle with CAPTCHAs, VPN users get blocked, and reading-mode users can render inconsistent fingerprints that prevent page loads altogether.

Agentic AI makes it worse. More traffic will come from a narrow set of IP ranges, and the underlying agents will share identical software and hardware platforms — stripping away most signal that distinguishes the honest from the malicious. Web Bot Auth would let agents reveal their platform of origin, but that mechanism is meant for the platform itself, not for distinguishing its individual users. Leveraging it for per-user controls would create unacceptable privacy risks.

That is where anonymous credentials and the Privacy Pass protocol come in. They offer a partially built answer: a way to enforce security controls on individuals without ever identifying them.

Blind signatures: simple but limiting

Privacy Pass rate limiting relies on a blind signature scheme. In conventional signatures, a signer uses a private key to sign a message and a verifier checks it with the public key. Blind signatures add a step: the client blinds the message before sending it, so the signer never learns what it is actually signing. The client later unblinds the returned signature to obtain a valid token.

RFC 9578 defines the standardized issuance flow:

  • Issuance: The user generates a random 32-byte string called the nullifier, blinds it, and sends the blinded value to the issuer. The issuer returns a blind signature, which the user unblinds to get a token — the pair (k, σ) of nullifier and signature.
  • Redemption: The origin verifies that σ is a valid signature for nullifier k and that k has never been seen before. If both hold, the request is allowed.

Blind signatures guarantee two properties: tokens are unforgeable (only the issuer can produce valid ones) and unlinkable (no party can tie a token back to the user it was issued to). They are simple, fast, and work for many scenarios — but they fall short for per-user, per-origin rate limiting in three specific ways.

First, the bandwidth cost is linear in the number of tokens. Each issuance involves a 256-byte blinded nullifier and a 256-byte blind signature (assuming RSA-2048), meaning roughly 0.5 KB of overhead per request, or 500 KB per 1,000 requests. VOPRFs (Oblivious Pseudorandom Functions) reduce compute time but have the same asymptotic bandwidth problem. Sublinear communication would be ideal for large rate limits.

Second, there is no way to bind a token to a particular origin after issuance. If a client redeems the same token at two different origin servers, those servers can correlate the redemptions and link them to the same client. What is needed is late origin-binding: a mechanism to transform a token for use at a specific origin without creating linkability across origins.

Third, issued tokens cannot be revoked or expired independently of the issuer's key. A token remains valid as long as the issuer's public key does. If an origin detects abuse or a token is compromised, it can block the offending request but cannot invalidate the user's remaining token budget.

Anonymous credentials add the missing pieces

Anonymous credentials, a concept dating back to Chaum's 1985 work, let a user obtain a credential from an issuer and later prove possession of it without revealing any extra information. They can be thought of as blind signatures with added capabilities relevant to rate limiting:

  • Late origin-binding: link a token to a specific origin after issuance, in a way that is unlinkable across different origins.
  • Multi-show: derive multiple single-use tokens from a single issuance session.
  • Independent expiration: decouple token validity from the issuer's cryptographic key lifecycle.

The key difference in the redemption flow is that the client reveals only part of the message. To be accepted, the client must prove knowledge of a valid signature over the full message — a presentation step that blind-signature-based tokens do not require.

A simplified example illustrates how stateful anonymous credentials can enforce rate limits. The client's credential consists of a pair (k, C) where k is a nullifier and C is a counter indicating how many more times the client may access a resource. On redemption, the server checks the signature, verifies that k is fresh, and that C is greater than zero. It then issues a new credential with an updated counter (C−1) and a fresh nullifier.

A blind signature could technically implement this, but only by keeping C in plaintext so the server can validate and decrement it. That creates a privacy leak: the server controls the counter and could use unique values to fingerprint and link the client's presentations across sessions.

ACT and ARC: two designs under consideration

The scheme above is a simplified version of Anonymous Credit Tokens (ACT), one proposal being considered by the IETF Privacy Pass working group. ACT's defining trait is statefulness: every successful redemption triggers a fresh credential issuance, creating a feedback loop between client and server that can express diverse security policies.

ACT's statefulness imposes a sequential constraint: a credential cannot be presented in parallel across multiple requests. Each presentation must complete before the re-issued credential can be used next.

Anonymous Rate-limited Credentials (ARC), another scheme under discussion in the same working group, takes a different approach. ARC's key feature is parallelism: a client can present credentials across multiple concurrent requests, up to a presentation limit fixed at issuance time. ARC also supports late origin-binding, allowing a single credential with limit N to be used N times at any verifier-capable origin.

Neither ACT nor ARC is a universal answer. The Privacy Pass working group is evaluating both because they are constructed from small sets of cryptographic primitives that can be adapted to other use cases. Which scheme wins out — or whether both are standardized — will depend on which features matter most for the deployment at hand.

Two primitives under the hood

ARC and ACT both build on two cryptographic primitives: algebraic MACs and zero-knowledge proofs (ZKPs). A MAC (Message Authentication Code) is a tag that proves a message's authenticity and integrity. Algebraic MACs, constructed over mathematical structures like group actions, add a useful property: a homomorphism that lets a client blind the MAC's value by combining it with a random value.

Unlike blind signatures, ARC and ACT are privately verifiable. The issuer and the origin must both hold the issuer's private key. A credential issued by Cloudflare, for instance, can only be redeemed by an origin behind Cloudflare. Publicly verifiable variants are possible but come at extra cost.

ZKPs let a prover demonstrate that a statement is true without disclosing the value that makes it true. The proof can only be generated by someone holding the secret, and a verifier can check it quickly. The proof itself reveals nothing beyond the statement's validity.

For ARC and ACT, the relevant statements are linear relations among secrets. In ARC, a user proves that different request tokens derive from the same issued credential. The system verifies this linkage without ever seeing the underlying credential. Such proofs can also establish ranges. To show a balance is positive, a user proves it can be encoded in binary bits and that a linear equation over those bits sums to the committed value. This works for powers of two and extends to arbitrary ranges.

The algebraic structure of the MACs enables straightforward blinding and evaluation. It also supports proofs that a MAC was evaluated with the private key, without revealing the MAC itself. ARC additionally uses ZKPs to prove a nonce hasn't been spent before, while ACT uses them to demonstrate sufficient remaining balance. In ACT, the balance is reduced homomorphically through the group structure.

Measuring the costs

Anonymous credentials offer flexibility and, in some applications, lower communication costs than blind signatures. To judge where they fit, we measured concrete communication and CPU costs across schemes.

All protocols were implemented in Go on Cloudflare's CIRCL library. ARC, ACT, and VOPRF used ristretto255 as the prime group with SHAKE128 for hashing; Blind RSA used a 2048-bit modulus with SHA-384.

For Blind RSA — the most widely deployed Privacy Pass mechanism — redemption is fast, and the server bears most of the cost at issuance. Communication is roughly constant at about 256 bytes.

Blind RSA
RFC9474(RSA-2048+SHA384)
1 Token
Time Message Size
Issuance Client (Blind) 63 µs 256 B
Server (Evaluate) 2.69 ms 256 B
Client (Finalize) 37 µs 256 B
Redemption Client 300 B
Server 37 µs

VOPRF shifts the balance: server verification is slightly more expensive than Blind RSA, but issuance and communication improve dramatically. Evaluation per token is 10x faster for a single token and over 25x faster with amortized batch issuance. Per-token message size drops by at least a factor of three, making VOPRF attractive for applications needing many tokens when higher redemption cost and lack of public verifiability are acceptable.

VOPRF
RFC9497(Ristretto255+SHA512)
1 Token 1000 Amortized issuances
Time Message Size Time
(per token)
Message Size
(per token)
Issuance Client (Blind) 54 µs 32 B 54 µs 32 B
Server (Evaluate) 260 µs 96 B 99 µs 32.064 B
Client (Finalize) 376 µs 64 B 173 µs 64 B
Redemption Client 96 B
Server 57 µs

For ARC and ACT, we measured the cost of issuing a single credential that permits up to N=1000 presentations.

Issuance
Credential Generation
ARC ACT
Time Message Size Time Message Size
Client (Request) 323 µs 224 B 64 µs 141 B
Server (Response) 1349 µs 448 B 251 µs 176 B
Client (Finalize) 1293 µs 128 B 204 µs 176 B
Redemption
Credential Presentation
ARC ACT
Time Message Size Time Message Size
Client (Present) 735 µs 288 B 1740 µs 1867 B
Server (Verify/Refund) 740 µs 1785 µs 141 B
Client (Update) 508 µs 176 B

Communication and server runtime for issuance are much lower than batched Blind RSA or VOPRF issuance. Issuing one ARC credential for 1000 presentations takes 1.35 ms, versus 99 ms for 1000 VOPRF tokens — roughly a 70x improvement. The trade-off: presentation costs more for both client and server.

ACT shows a similar pattern in issuance cost. Performance differs from ARC in notable ways: ACT issuance is cheaper, but redemption is more expensive. The reason lies in the ZKP statements each party proves. ACT redemption requires the client to prove in zero-knowledge that its counter falls within the desired range; the proof size scales with the logarithm of the range, accounting for the larger messages.

ARC redemption currently avoids range proofs entirely, though one may be added in a future revision. ARC issuance, meanwhile, involves more complex statements than its presentation phase, explaining the runtime differences.

The real appeal of anonymous credentials is that issuance happens once. When evaluating total cost, a server must weigh all issuances against all verifications. Today, for pure credential costs, it's still cheaper for a server to issue and verify individual tokens than to verify one anonymous-credential presentation. But multiple-use credentials offload most computation to clients and enable features single-use tokens cannot support: late origin binding across multiple origins, range proofs that decouple expiration from key rotation, and refunds for dynamic rate limiting. These capabilities — not raw efficiency — define their current niche.

Managing agents with ARC and ACT

Practical agent management will likely draw from both schemes.

ARC alone covers rate limiting, communication efficiency, and late origin binding. Its weakness is irrevocation: once issued, a credential allows up to N requests to any origin, with no way to take it back.

Pairing ARC with blind signatures or VOPRF enables a limited form of revocation. Each ARC presentation accompanies a Privacy Pass token. On successful presentation, the client receives a fresh token for the next round. To revoke, the server simply declines to re-issue:

BLOG-3027 image 5

This hybrid has limitations:

  • It prevents parallel presentations: a client must wait for one origin's request to finish before approaching another.
  • Revocation is global, not per-origin. One origin's revocation blocks the credential everywhere, which may be undesirable when a single request violates one origin's robots.txt policy but would have been accepted elsewhere.

The deeper limitation is that revocation decisions rest on a single request — the one presenting the credential. Attack patterns often emerge only over many requests, making single-request judgments risky. ACT's statefulness allows a rudimentary defense-in-depth:

  • Issuance: The client receives an ARC credential with presentation limit N=1.
  • Presentation:
    • On first ARC presentation, the origin issues an ACT credential with a valid initial state.
    • On each subsequent ACT presentation, the origin either issues an updated ACT with reduced credit (reflecting resources consumed) or refuses to issue a new ACT, revoking the credential when confident the request was part of an attack.

Benign requests barely alter the state, if at all. Suspicious requests deplete the credit faster, pushing the user toward the rate limit more quickly.

Working demo via MCP

A practical implementation of this rate-limiting approach is available using the Model Context Protocol (MCP). The demo leverages MCP Tools — extensions an AI agent can call, which don't require integration at release time into the MCP client. This makes them a convenient prototyping surface for anonymous credentials.

In this scenario, a pizzeria issues a voucher good for three pizza slices. An MCP server exposes two tools that agent can invoke:

  • act-issue — issues an ACT credential valid for three requests.
  • act-redeem — presents the credential and fetches the pizza menu.
BLOG-3027 image 6
BLOG-3027 image 9

To test the flow, we run act-issue first. At this stage, the agent might perform an OAuth flow, authenticate against an internal endpoint, or compute a proof-of-work, depending on the use case.

image10

We now have three credits to spend. After running act-redeem:

image8

A second call to act-redeem shows the remaining credits decrement as expected:

image3

The full reference implementation is available on GitHub — an MCP server written in Rust using the MCP Rust SDK and the ACT Rust library. A browser-based client demonstrates similar behavior.

Open questions and path forward

This approach puts rate limiting under the client's control while protecting user privacy. It builds on emerging anonymous credential standards, fits into MCP, and is deployable on Cloudflare Workers. Still, significant questions remain.

A key limitation of both ARC and ACT is that they are only privately verifiable — issuer and origin must share a private key for issuing and verifying credentials. Some deployments can't accommodate that requirement. Pairing-based cryptography may provide an answer, as suggested by the BBS signature specification progressing through the IETF. Cloudflare is also examining post-quantum implications in a concurrent post.

The code is open for experimentation by agent platforms, developers, and browser vendors. Specification work continues openly within the IETF and W3C, with remaining tradeoffs around performance versus privacy and deployment on the open web still to be resolved. Cloudflare is actively evaluating the approach for real-world adoption.