2026-07-15
AI Agent Traffic Authentication: A 32-Case WBA Gate
A failure-first Web Bot Auth drill shows why an AWS WAF verified label must still pass origin route, rate, replay, content, and application-authorization gates.
Failure-first WBA policy drill
A green Web Bot Auth label is not an authorization decision. It says AWS WAF validated a signed automated request against a known public key. It does not say the bot may use this hostname, route, method, account, rate, or application action.
That distinction is easy to lose because the current Bot Control documentation says a web_bot_auth:verified request no longer matches CategoryAI and TGT_TokenAbsent. The request can pass those managed-rule checks and still deserve a rejection at the next boundary.
We translated the boundary into a 32-case local admission ledger. One signed read and one separately authenticated write passed. One signed write stopped for application step-up. The other 29 packets failed on identity, coverage, freshness, replay, route, rate, or WAF-order controls.
587688811d18e4106f0f524f38504eb83662af397fd08c334154f2e2e7860c06.The signature ends one argument and starts another
IP ranges and user-agent strings are weak identity evidence for multi-tenant agent platforms. A copied header is free. A shared egress address can represent thousands of unrelated workloads. Web Bot Auth addresses that problem by binding selected HTTP components to an asymmetric key and publishing the matching public key through a signature directory.
A successful verification settles a narrow question: did the holder of this key sign the covered request components inside the accepted time window? The origin still owns the consequential questions. Is this exact bot identity registered? May it read this collection? Can it mutate a ticket? Is the request volume plausible? Has the nonce already been consumed?
Authentication narrows the principal. Policy narrows the action.
These counts describe our deterministic policy fixture, not AWS WAF conformance coverage and not a live service test.
Validation ledger: what AWS puts on the wire boundary
The current AWS Bot Control rule-group documentation lists four Web Bot Auth outcomes under the awswaf:managed:aws:bot-control:bot: namespace. The same request can also carry bot name, category, organization, vendor, and—for Amazon Bedrock AgentCore—an opaque account label. Those fields are useful precisely because a bare “verified” result is too broad for origin policy.
| WBA result | What it establishes | What it does not establish | Our first action |
|---|---|---|---|
verified | The signature validated against the public-key directory. | Route permission, application scope, safe rate, benign intent, or replay safety. | Continue to identity and route policy. |
invalid | Signature material was present but cryptographic validation failed. | Whether the failure was an attack, corruption, or bad rollout. | Block and preserve a bounded diagnostic sample. |
expired | The signature used expired cryptographic key material. | Whether a rotation cache or retired signer caused the event. | Block and page the key owner. |
unknown_bot | The key identifier was absent from the verifier's directory view. | Whether registration is pending or the identity is fabricated. | Block protected routes; measure public-route demand separately. |
Rule order matters. Bot Control must evaluate before a label-matching rule can consume its output. A static managed-rule version also belongs in the deployment record; quietly floating the version changes the verifier while the origin policy appears untouched. The managed group currently consumes 50 WCU, so capacity and cost belong in the change review too.
A passing packet carries more than a green label
Our allowed read targets GET /knowledge/runbooks on one hostname. The synthetic request uses TLS, covers authority, method, path, and the signature-directory reference, stays inside a two-minute freshness window, presents an unseen nonce, matches the registered vendor/account/name tuple, stays under 30 requests per minute, and has no managed threat signal.
Remove any one of those controls and the decision changes. That may look strict for a read path. It is also reviewable: every acceptance fact is visible in one ledger row rather than implied by a generous WAF allow rule.
Keep those rails separate in telemetry. A single “agent allowed” counter cannot tell whether signatures are failing, registration drifted, rate policy is too tight, or the application rejected a perfectly authenticated writer.
Coverage is the quiet security boundary
RFC 9421 lets an application sign selected HTTP fields and derived components. Selection is powerful and dangerous. A valid signature over the wrong set of components can authenticate bytes that do not constrain the action the server eventually performs.
The Web Bot Auth architecture draft requires at least @authority or @target-uri. Our admission policy goes further for protected routes: it also requires @method, @path, and the directory reference. A write additionally requires a covered content digest. Without those bindings, an intermediary or replay path can preserve a valid signature while moving the request to a different operation.
TLS remains mandatory. HTTP Message Signatures add authenticity and integrity for covered components; they do not encrypt the payload, and RFC 9421 explicitly treats confidentiality as a separate property.
Failure modes: replay changes with consequence
A repeated crawl of a public document and a repeated refund are not equivalent failures. Both can carry valid signature bytes. Only the application knows whether duplication is harmless, idempotent, expensive, or irreversible.
The local ledger rejects missing and previously seen nonces. It also caps both signature age and forward expiry at 120 seconds. Those numbers are a policy choice for this fixture, not an AWS default. A real cache must define its scope, eviction behavior, clock-skew tolerance, and outage posture before enforcement.
Do not put a global replay cache in front of every route without modeling its memory and failure mode. A low-risk read may accept bounded duplication during cache degradation. A mutation should instead use an application idempotency key whose result can be replayed safely, or fail closed if that store is unavailable.
Why the signed write stopped
One fixture packet had a valid WBA identity, correct host and route, covered method/path/content digest, fresh timestamps, and an unseen nonce. It still returned REQUIRE_APPLICATION_AUTH. The missing facts were an application token and an intent identifier bound to the business action.
This is deliberate. Bot identity describes the automation operator. Application authorization describes the user, tenant, delegated scope, approval state, and object being changed. Collapsing the two creates a universal credential: compromise one browser signer and every origin action gated only by “verified” becomes available.
The fully accepted write adds the narrow application facts and stays under a four-per-minute write limit. Its WBA signature is necessary but insufficient. That is the policy shape worth preserving.
Rotation has two clocks, not one
A bot operator publishes public keys; AWS WAF polls directories and maintains a registry. The operator therefore controls signer rotation while the verifier controls refresh timing. The origin sees the consequences as verified, expired, or unknown_bot labels.
A rotation drill should observe all three systems. Introduce the new key, wait for verifier recognition, canary signed reads, move traffic, retire the old key, and prove the retired key no longer reaches the origin policy. Record directory publication time, first verified observation, last old-key observation, and the rollback owner. “New key exists” is not a completion criterion.
Keep the signing key outside prompts and model-visible logs. AgentCore Browser can sign automatically when WBA is explicitly enabled at browser creation, but AWS still describes the feature as preview and based on an evolving IETF draft. Pin assumptions to a test date rather than promising a permanent header shape.
The rollout has three reversible cuts
First, observe. Add Bot Control, pin the selected static version, preserve ordinary managed protections, and count each WBA outcome by host, path, bot identity, and action. Do not create a broad verified-bot allow rule.
Second, constrain reads. Register exact vendor/account/name tuples and open one low-consequence path with a route-specific rate. Run unsigned, invalid, expired, unknown, stale, replayed, cross-host, cross-path, and excessive-rate cases. Each should land in the expected bucket.
Third, step up writes. Cover method, path, and content digest; bind an application identity and intent; add idempotency; use a tighter rate; and rehearse loss of the nonce or idempotency store. Expand only after the negative cases are as observable as the happy path.
Pinned records behind the decision
- AWS Security Blog: Authenticate legitimate AI agent traffic with AWS WAF Bot Control — service architecture, directory polling, asymmetric verification, and implementation walk-through.
- AWS WAF Bot Control rule-group documentation — current WCU, label namespace, WBA outcomes, identity labels, and verified-label rule behavior.
- AgentCore Browser Web Bot Auth documentation — preview boundary, automatic signing, explicit enablement, headers, vendor coverage, and website-owner control.
- RFC 9421: HTTP Message Signatures — covered components, verification, replay, TLS, and confidentiality considerations.
- Web Bot Auth architecture draft-05 — bot-specific signature coverage and parameter requirements used for this dated analysis.
- Local admission fixture — 32 decisions, zero mismatches, and 29 blocked mutations. SHA-256:
587688811d18e4106f0f524f38504eb83662af397fd08c334154f2e2e7860c06.
The retained harness is deterministic JavaScript over synthetic packets. It did not access an AWS account, create a WAF web ACL, start AgentCore Browser, sign a real request, fetch a public-key directory, touch a protected origin, read credentials, or alter production traffic.