Skip to main content
Security Auditor — verifies the signed key directory at /.well-known/http-message-signatures-directory that origins such as Cloudflare use to recognise your bot.

Bot verification

Cloudflare Verified Bots and any RFC 9421 verifier look up your public keys in this directory before trusting your crawler.

Signed directory

The directory response itself must be signed by each key it publishes, with a short, unexpired validity window.
This auditor is for sites that operate a bot and sign its requests with Web Bot Auth. It audits the key directory the site serves, not the requests the bot sends: only the directory is observable from the outside.

How it works

The auditor ports the checks of Cloudflare’s http-signature-directory validator:
  1. Locate — builds <scheme>://<host>/.well-known/http-message-signatures-directory from the audited URL (its path is ignored) and fetches it with Accept: application/http-message-signatures-directory+json, following redirects.
  2. Blocked or missing — HTTP 403, 429 or a Cloudflare challenge ends the run as a blocked bot (590). Any other non-2xx status fails (400): a bot owner without a reachable directory cannot be verified.
  3. Keys — parses the body as a JWKS. Each key must be an OKP key on curve Ed25519 with a 32-byte base64url x. The RFC 7638 thumbprint of each key is the keyid verifiers expect.
  4. Signatures — reads Signature-Input and Signature. For every key there must be an entry with tag="http-message-signatures-directory", keyid equal to the thumbprint, created, expires and the ("@authority";req) component. The entry must not be expired, and the Ed25519 signature must verify over the RFC 9421 signature base built from the final response URL.
  5. Hygiene — warns when the directory is served over http, with the wrong Content-Type, or with a Cache-Control lifetime longer than the signature’s remaining validity (a cached copy would be served with an expired signature).
  6. Aggregate — ERROR wins, then FAIL, then WARNING; if every rule passes, the audit is SUCCESS.
  7. Specification pin — every run emits 37A-WebBotAuthAuditor-100 (INFORMATION) naming draft-meunier-http-message-signatures-directory-03 and RFC 9421. That check does not change overall status.

What it audits

Every row maps to one checkRule* method and one CheckCode. 37A-WebBotAuthAuditor-100 is emitted on every run, including fetch errors. Key rules (403–409) run once per published key, so one audit can carry several checks with the same code. 401 skips every later FAIL rule; 402 skips the key rules; a key that fails 403 or 404 skips 406–409; 405 skips 406–409 for all keys; 406 skips 407–409 for that key; 407 skips 408 and 409. CheckCode suffixes use status ranges: 100 information, 200 success, 300–399 warning, 400–499 fail, 500–599 error.

Output documentation

Risks and considerations

An unverifiable bot is an anonymous bot

  • Cloudflare and other origins verify your crawler by fetching this directory and checking the signature on it. A missing, unsigned or expired directory makes every signed request from your bot look unverified, and bot protection treats it like any unknown crawler.
  • Rotate keys by publishing the old and the new key together, each with its own directory signature, until the bot has switched.

Caching silently breaks signed directories

  • The directory response is signed with a created/expires window. A CDN, framework cache or static export that serves the same response past expires hands verifiers an expired signature. Sign on every request, or keep the cache lifetime below the validity window.

What this auditor does not check

  • The bot’s own signed requests (tag="web-bot-auth", the Signature-Agent header) leave the bot, not the site, so they cannot be audited from the outside. Use Cloudflare’s crawltest.com to test those.
  • The content-digest component the draft recommends is not required; Cloudflare’s validator does not require it either.
  • Registration with Cloudflare Verified Bots is a separate submission and is not verified.