# For site owners: what a Whisper agent is, and how to verify one

**A request from a Whisper agent comes from an address you can look up. This page is for the people who run the sites those requests reach: what the agent is, the three ways to check one, what we do not promise, and where to report one.**

Every capture on this page was taken from production on 2026-11-02 with stock tools and no account. Re-run any of them yourself; the commands are the evidence.

## What a Whisper agent is

A Whisper agent is software acting for a person who asked it to do something: an AI assistant fetching a page, a script calling an API, a device phoning home. In Cloudflare's terms it is an intermediary acting on a user's request, not a crawler. It does not roam the web looking for pages to index.

Each agent holds exactly one IPv6 address, a `/128`, out of `2a04:2a01::/32`. That block is registered in the RIPE database to viaGraph b.v. as `WHISPER-AGENTS` and originated by our own network, AS219419:

```
$ whois -h whois.ripe.net -B 2a04:2a01::/32
# (filtered to the lines that matter)
inet6num:       2a04:2a01::/32
netname:        WHISPER-AGENTS
org:            ORG-VB155-RIPE
status:         AGGREGATED-BY-LIR
route6:         2a04:2a01::/32
origin:         AS219419
```

The route is RPKI-valid (RIPEstat `rpki-validation` for AS219419 and `2a04:2a01::/32` returns `valid`). One address is one agent, so one agent can be allowed, rate-limited or blocked on its own without touching any other.

## How to verify one

Three methods, from the cheapest to the strongest. Use whichever your stack already speaks.

### 1. The published range

```bash
curl -s https://whisper.online/.well-known/agent-ranges.json
```

```
{
  "creationTime": "2026-09-24T00:00:00.000000",
  "prefixes": [
    {
      "ipv6Prefix": "2a04:2a01::/32"
    }
  ]
}
```

The same shape Google, OpenAI and Anthropic publish for their own agents, so an allow-list that already reads theirs can read ours. A source address inside the prefix is a Whisper agent's address. On its own that tells you the network, not which agent; the next two methods tell you which one.

### 2. Forward-confirmed reverse DNS

The reverse name of an agent's address points at the agent's name, and that name points back at the same address. Both answers are DNSSEC-signed, so validate them in your own process with `delv` rather than trusting a resolver's `AD` bit (RFC 4035 section 4.9.3 explains why a stub must not rely on it).

```bash
SRC="2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4"
name=$(dig +short -x "$SRC")
fwd=$(dig +short AAAA "$name")
[ "$fwd" = "$SRC" ] && echo "FCrDNS OK: $name" || echo "FCrDNS FAIL"
```

```
FCrDNS OK: acef2002a323d40d4.t7af9242c44554e0f8e183ac8e6fbf645.agents.whisper.online.
```

```bash
delv @1.1.1.1 -x "$SRC"
delv @1.1.1.1 AAAA "$name"
```

```
; fully validated
4.d.0.4.d.3.2.3.a.2.0.0.2.f.e.c.4.7.a.c.a.5.b.e.1.0.a.2.4.0.a.2.ip6.arpa. 60 IN PTR acef2002a323d40d4.t7af9242c44554e0f8e183ac8e6fbf645.agents.whisper.online.
; fully validated
acef2002a323d40d4.t7af9242c44554e0f8e183ac8e6fbf645.agents.whisper.online. 60 IN AAAA 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4
```

Two things to know before you write the rule:

- **Match on the reverse zone, then forward-confirm.** Most agents are named under `.agents.whisper.online`, but an agent minted under a customer's own domain is named under that domain instead (a live one answers `a4f988041b1326d8a.everwatch.io.`). The part that is always ours is the reverse zone, `1.0.a.2.4.0.a.2.ip6.arpa`, which only AS219419's servers can sign. So the rule is: the source is in `2a04:2a01::/32`, its PTR validates, and the forward lookup of that PTR returns the same address.
- **An unused address vouches for nothing.** An address in the block that is not allocated to an agent has no PTR at all:

```
$ dig -x 2a04:2a01:9::50 @1.1.1.1
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN
1.0.a.2.4.0.a.2.ip6.arpa. 300 IN SOA ns1.whisper.online. hostmaster.whisper.online. ...
```

If you would rather have one answer than run the legs yourself, the same chain is checked by a keyless endpoint, and its registry record is in RDAP:

```bash
curl -s https://rdap.whisper.online/verify-identity/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 \
  | jq '{is_whisper_agent, fqdn, tenant, dane_ok}'
curl -s https://rdap.whisper.online/ip/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 | jq '{handle, name, status}'
```

```
{
  "is_whisper_agent": true,
  "fqdn": "acef2002a323d40d4.t7af9242c44554e0f8e183ac8e6fbf645.agents.whisper.online",
  "tenant": "t7af9242c44554e0f8e183ac8e6fbf645",
  "dane_ok": true
}
{
  "handle": "acef2002a323d40d4",
  "name": "docs-example-1",
  "status": [
    "active"
  ]
}
```

An address we do not hold returns `{"is_whisper_agent": false}`, never an error.

### 3. Web Bot Auth (HTTP message signatures)

Requests an agent sends through our fetch-forward gateway are signed under RFC 9421 in the Web Bot Auth profile. Each signed request carries three headers:

| Header | What it holds |
|---|---|
| `Signature-Agent` | `sig1="https://whisper.online"`, the origin that serves our key directory |
| `Signature-Input` | label `sig1`, covering `"@authority" "@method" "@path" "signature-agent";key="sig1"`, with `alg="ed25519"`, `tag="web-bot-auth"`, and a five-minute `created` to `expires` window |
| `Signature` | the Ed25519 signature over that base |

The key directory is public, and the directory response is itself signed, so a verifier can tell it came from the host it asked:

```bash
curl -sSD - https://whisper.online/.well-known/http-message-signatures-directory
```

```
HTTP/2 200
cache-control: public, max-age=86400
access-control-allow-origin: *
content-digest: sha-256=:h3XU+z1rrGFstvY2wS5DKryy6t36Qw7Wy87T2RDyebk=:
signature-input: binding=("@authority";req "content-digest");created=1793577600;expires=1794182400;keyid="5HtlED7Zf1gV7QBh9t6OINT4XvoBTvvRPrrPTI2Ukp4";tag="http-message-signatures-directory"
signature: binding=:XIAfIvvAtx7hBEkoljz7YuW8A0AlgfgUVjO1fhPIN4qsWn7Av+XTfBoMjenh/iQKXcWEVui8aptg1VddAwmzAA==:
content-type: application/http-message-signatures-directory+json

{"keys":[{"kty":"OKP","crv":"Ed25519","alg":"ed25519","use":"sig","kid":"5HtlED7Zf1gV7QBh9t6OINT4XvoBTvvRPrrPTI2Ukp4","x":"G8aeCZXIhoI0V8nxSYie1goVNiSun6BPOvLYNFTYYjM","nbf":1790294400,"exp":1796169600}]}
```

The `kid` is the RFC 7638 thumbprint of the key. The same directory is served at `https://agents.whisper.online/.well-known/http-message-signatures-directory`.

Which traffic is signed depends on how the agent leaves our network:

| How the agent connects | Source address your site sees | HTTP signature | Reverse DNS |
|---|---|---|---|
| fetch-forward gateway (`forward.whisper.online`) | the agent's `/128` | yes | yes, forward-confirmed |
| SOCKS5 or HTTP CONNECT proxy | the agent's `/128` | no: a TCP tunnel, TLS runs end to end between the agent and you | yes, forward-confirmed |
| WireGuard (routed `/128`) | the agent's `/128` | no: packets, TLS runs end to end | yes, forward-confirmed |

We cannot sign inside a TLS session we do not terminate, and we do not break TLS to do it. For tunnelled traffic, methods 1 and 2 are the check.

## What we do not promise

- **It is not a crawler.** Whisper agents fetch what a person asked for. We run no crawler under this range.
- **The User-Agent is the caller's own.** We forward it unchanged and add no product token, so do not identify a Whisper agent by its User-Agent: use the address, the reverse name or the signature. Whether the fetch-forward gateway should append a fixed token is an open decision; it would change the bytes we emit, so it has its own issue.
- **robots.txt is the agent's responsibility.** On a fetch a person asked for, honouring robots.txt is the agent operator's call, as it is for any browser. Each agent's owner is named in its RDAP record, and you can report one that misbehaves (below).
- **IPv4 is not covered.** Everything above is about IPv6. When an agent reaches an IPv4-only site, the connection leaves from a shared address that is not in `agent-ranges.json` and has no Whisper reverse DNS, so none of the three methods applies to it. Giving agents a published IPv4 range is open work.
- **No vendor recognition is claimed.** This page does not say any bot-management vendor already recognises Whisper agents. It will say so for a vendor only once that vendor has confirmed it.

## Report an agent

Write to **security@whisper.security**. It is also the `abuse-mailbox` of `AR80195-RIPE`, the abuse contact on `ORG-VB155-RIPE`, so `whois` hands it to anyone who asks:

```
$ whois -h whois.ripe.net -B AR80195-RIPE
# (filtered to the lines that matter)
role:           Abuse-C Role
abuse-mailbox:  security@whisper.security
```

Send the source `/128`, the time in UTC, and what it did (log lines are ideal). Each `/128` is one agent and is revocable on its own: once revoked, `dig -x` on the address returns nothing and `/verify-identity` returns `is_whisper_agent: false`, so the same tools that identified it show it is gone. Reporting one agent never affects any other.

**Next:** [Access control](/docs/access-control) - authorize on a confirmed name · [Reverse DNS & FCrDNS](/docs/reverse-fcrdns) - the threat model behind method 2 · [Verify an agent](/docs/verify) - every proof, including the trustless one
