Security

Threat model

What a verification proves and what it does not, which values are public, and the attacks the protocol is designed to resist.

The claim

This request was signed by a recognized agent credential.

That is the whole statement. A VERIFIED result means someone holding the private key for an active, registered key of a non-disabled agent signed this specific challenge within its validity window. For web_bot_auth, it means the request was signed by a key listed in the named origin's key directory.

What is not proven

  • That no human was involved. A human can run, script or supervise an agent, or paste a challenge URL into a terminal. The signature proves possession of a key, not the absence of people.
  • That the agent is benevolent, accurate or safe. Registration does not vet behaviour.
  • That access should be granted. The token identifies a credential; your site decides what that credential may do. There is no authorization delegation in the protocol.
  • Who the operator is. Agent names and websites are self-declared by the registering account.
  • Anything about the agent's later requests. The token covers one challenge; it is not a session.

Public values

ValuePublic?Why it is safe
Site keyYesOnly creates challenges, and only from allowed origins. Possession grants nothing else.
Challenge idUnguessable128 bits of entropy; acts as the handle for polling. Knowing it lets you observe the outcome and submit proofs, not forge them.
NonceYesA freshness value bound into the signature. Its secrecy is not required.
Public keysYesRegistered for verification; served in JWKS for the token signing key.
TokenBearerAnyone holding it can present it once. Send it only to your own backend over HTTPS.
Registration token (reg_…)SecretSingle-use, 15-minute credential that binds a key to an agent. Only its hash is stored.
Private keysSecretNever leave the agent.

Attacks considered

AttackMitigation
Forging a verified widget stateThe widget only reflects server state; hosts must verify the token server-side.
Replaying a proofChallenges are consumed on first valid proof; created must be within ±60 s; the base binds challenge_id and nonce.
Replaying a tokenTokens are single-use with consume: true; exp is 10 minutes; jti is unique per challenge.
Using a token on another siteaud is the site key; verify with site_key. Origin is embedded in the token.
Creating challenges from a phishing pageOrigin header is required and must match https://<domain>, https://*.<domain> or an allowed origin.
Brute-forcing signaturesEd25519 (128-bit security); 10 attempts per challenge; per-network, per-site and per-agent rate limits.
Flooding mint, verify, registration or health429 RATE_LIMITED with Retry-After. Budgets are per address, per site and per agent. A verified credential does not raise them.
Tampering with challenge fieldsThe server rebuilds the signature base from its own record; client fields are only used to look up the challenge.
Substituting the signing algorithmOnly Ed25519 proofs and EdDSA tokens are accepted; alg is fixed in both.
Using a revoked or pending keyKey and agent status are checked on every proof: KEY_REVOKED, KEY_PENDING, AGENT_DISABLED, AGENT_REVOKED.
Passing a test token as liveTest tokens are rejected unless allow_test is set explicitly.
Directory spoofing (Web Bot Auth)https only, no redirects, public hosts only, size and count limits, thumbprint-based key selection.

Out of scope

  • Compromise of the agent host: whoever controls the private key is the agent.
  • Compromise of the host page: a malicious script can hide the widget or forward the token elsewhere. Server verification limits the damage to one use.
  • Denial of service beyond the documented rate limits.
  • Reputation, behaviour analysis and scoring: not part of the product.