Whisper · Docs
Content

Content

A valid Content Credential proves the pixels weren't changed. It can't tell a stranger whether to trust the signer.

A C2PA manifest carries a cryptographic claim signature: a COSE_Sign1 with the signer's full X.509 chain embedded in-band (RFC 9360 x5chain). Any verifier can confirm, with no network call, that the asset's bits weren't altered since signing. What it can't answer is the question that actually decides trust: should I trust this signer? Today that answer lives in a coalition-curated Trust List, or nowhere. Whisper closes that gap with one primitive: the signer's address is its identity, a publicly verifiable, DNSSEC/DANE-anchored, revocable name for the signer your manifest already references. This page is the content front door to the Whisper docs. The full technical library (DNSSEC, DANE, RDAP, the control-plane API) sits one click down the sidebar, identical to whisper.online/docs.

The problem: "unknown source", and no Let's Encrypt for C2PA

A C2PA validator trusts a signer only if its certificate is on an explicit allowed list, or chains to a root on a trust-anchors list. The spec is deliberately unopinionated about which list: trust lists and anchors are pluggable configuration inputs to the validator. But in practice one list dominates: the official C2PA Trust List + Conformance Program (launched mid-2025), a coalition-curated set of CA anchors gated by a Product Security Architecture submission and assurance levels 1/2. Content signed by a certificate off that list renders as "unknown source", technically identical, in the manifest, to a manifest from a verified organization. The burden shifts entirely to the verifier to resolve who the signer is, and there is no free, automated, ACME-style path for an independent creator, a small newsroom, a stringer, or an AI agent to become a recognized signer; commercial C2PA certificates run on the order of ~$289/yr. The gap has a widely-used name: there is no Let's Encrypt for C2PA.

This is not a bug Whisper invented a story around. It is C2PA's own stated dependency. The spec says trust rests on "an identity ecosystem substantiating the signing key belongs to the Signer." C2PA provides the signature format and a curated CA list; it does not provide that public identity ecosystem. Two more edges sharpen it:

And there is no feedback loop. Because the whole chain travels in the manifest, verification needs no network call, so once content is published, the signer has zero visibility into who verified it, where, or how often.

A valid signature, and still no public answer to "should I trust this signer?" Content Credential COSE_Sign1 · x5chain signer EE cert + serial hard binding ✓ (bits intact) signer trust ✗ (unresolved) C2PA Trust List curated coalition · assurance L1 / L2 ~$289/yr CA · no ACME path Re-encode / screenshot manifest (JUMBF) stripped credential gone entirely off-list no manifest Receiver can't decide "unknown source" for off-list signers no credential on the stripped asset the public identity ecosystem is missing
C2PA proves the bits weren't changed. But whether to trust the signer routes through a coalition-curated Trust List (off-list signers show "unknown source", with no free, automated path onto it), and a screenshot or re-encode can strip the manifest outright. The signature is sound; the public identity ecosystem it depends on is the missing piece.

Honest scope, up front. Anchoring the signer does not stop a screenshot or a heavy re-encode from separating the credential. That is watermarking's and durable soft-binding's job, and Whisper pairs with them rather than replacing them. It does not make signed content true: provenance is origin and history, not veracity, and a genuine signer can sign a photograph of a screen. And it is not a deepfake detector: the absence of a credential is not proof of fakery. What Whisper adds is the one layer none of these give you: a publicly verifiable, revocable signer identity, plus the analytics to see who checked it.

The cure: the address is the signer

Shipped & live. Deriving a signer /128 from the C2PA signing key it already holds, with the signer-cert serial as device_id, DNSSEC + DANE-EE pinned and RDAP-registered, is in production today. Provision one with the control-plane call below, then verify it from the DNSSEC root with tools already on your machine.

Whisper gives each signer a routable IPv6 /128 out of 2a04:2a01::/32 (announced by AS219419), derived deterministically from the signer's public key: the SubjectPublicKeyInfo of the C2PA claim-signer EE certificate (or a CAWG identity credential's key), with the signer-cert serial as the domain separator. The private key never leaves the signer's HSM or key store; only its public SPKI is an input. The result is DNSSEC-anchored, DANE-EE 3 1 1 pinned, and RDAP-registered, re-derivable and verifiable by anyone with dig. Publish that same EE certificate as a DANE TLSA record under your own DNSSEC-signed domain and the signer becomes self-verifying: any relying party can pin it with no central list to join, no gatekeeper, and no annual CA fee. That's the missing "Let's Encrypt for provenance."

Signer's C2PA EE key COSE signer cert · SPKI cert serial = device_id private key stays with the signer only the public SPKI is an input public key + serial /128 2a04:2a01:c2a::51 routable · tenant-bound serial alone yields nothing DNSSEC + DANE-EE 3 1 1 A signer anyone can verify whisper verify --trustless a pluggable anchor, via CAWG no Trust List · no CA toll RDAP-registered under AS219419 op:'revoke' → signer untrusted worldwide at DNS-TTL
The signer's own public key derives the address; DNSSEC + DANE-EE 3 1 1 publish the binding under the signer's own domain, so any validator can pin the signer with no central list to join and no ~$289/yr CA toll. Because trust anchors are pluggable validator inputs, this is additive to C2PA, never a fork, surfaced through a CAWG identity assertion. One revoke pulls a compromised signer worldwide at DNS-TTL: the off-switch optional OCSP never delivered.

A legitimate, pluggable trust anchor: additive, never a fork. Because C2PA treats trust lists and anchors as validator configuration inputs, a DNSSEC/DANE anchor is a legitimate alternative trust source, not a re-invention of the standard. The manifest stays yours; the signer becomes publicly verifiable. Be candid about one thing, though: DNSSEC/DANE is not (yet) a formally recognized C2PA conformance trust anchor. Today conformance centers on X.509 and the curated C2PA Trust List. The clean way to surface it in-ecosystem is through CAWG: the Creator Assertions identity assertion carries a did:web issuer and a cawg.web_site URI that are already DNS-native, so a Whisper DNSSEC-anchored domain is a first-class did:web root. DANE-bind your cawg.web_site.uri and your cawg.x509.cose organization certificate and you turn a well-formed-but-unrooted identity into a trusted one without an S/MIME CA. It also directly answers C2PA's own Web Domain Trust Anchor experiment, with the mechanism that proposal didn't use: a DNSSEC-signed record instead of an HTTPS file a domain takeover subverts.

Because the derivation is tenant-bound, the same signing key under two different organizations yields two unrelated /128s. No outsider can link a signer across a publisher, a syndication partner, and a stock agency. And because the domain separator is the cert serial, the serial alone yields nothing: you cannot go serial → /128 without the key, there is no enumerable directory, and RDAP and reverse-DNS return the registry object, never a map of who signs what.

What becomes true the moment a signer holds one:

Additive, never a replacement. Whisper complements the pieces the ecosystem already does well and does not touch: the C2PA manifest and its edit history, the CAWG identity assertion, the RFC 3161 TSA time-stamp that keeps a manifest valid past cert expiry, a durable watermark (SynthID, Meta Seal) or Durable Content Credentials that recover a binding after a strip, and in-camera hardware signing. Whisper does not create the manifest or embed the watermark. It anchors the signer the manifest already references, and adds the analytics and revocation the rest of the stack lacks. It maps cleanly to the EU AI Act's named technique, Recital 133's "cryptographic methods for proving provenance and authenticity of content," made accessible to the public via open DNS, without ever claiming to make anyone compliant. More in EU AI Act · C2PA · ISO 22144.

Provision a signer identity

Provisioning is one control-plane call over the public API: POST https://graph.whisper.security/api/query with your X-API-Key. Hand it the base64 SPKI of your C2PA signing certificate and the device_id (the signer-cert serial, or a CAWG identity / did:web), and it returns the deterministic /128 and a WireGuard config for source-bound egress:

CALL whisper.agents({op:'connect', args:{
  tier:'wireguard',
  identity_public_key:'<base64 SPKI of the C2PA signer cert key>',
  device_id:'03ac74f29e1b5580'   // the C2PA signer-cert serial; or a CAWG id, e.g. 'did:web:example-news.org'
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error

Send it with your key. The heredoc keeps the single-quoted Cypher literals intact, so this runs as-is:

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H 'content-type: application/json' \
  --data @- <<'JSON'
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard', identity_public_key:'<base64 SPKI>', device_id:'03ac74f29e1b5580'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
# response
{ "op": "connect", "ok": true, "status": "created",
  "result": {
    "address": "2a04:2a01:c2a::51",
    "fqdn":    "signer-03ac74f2.c2pa.<tenant>.agents.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips */ }
  } }

The call is idempotent, liberal in what it accepts, strict in what it returns: re-running with the same key and device_id returns the same /128; a different device_id for a key already registered on your tenant is a clear 409, not a silent overwrite; a non-string device_id is a 400 that tells you exactly what was wrong, never an opaque 500. To publish the DANE record under your own newsroom or studio domain (so readers verify "signed by example-news.org"), prove the domain once with op:'domain' and issue the signer under it. See C2PA · CAWG · newsroom.

i

A first-class typed --signer-cert / --cawg argument is on the roadmap. Today, signer provisioning is the control-plane call above (which is live): pass your signer-cert serial or CAWG identity as device_id. The shipped CLI verbs are whisper verify --trustless, whisper create --register, whisper kill --revoke, whisper policy, and whisper logs. See CLI & one-command.

Verify it yourself (no account)

Every signer identity is checkable with no key and no login, from the internet's own records. The whisper CLI does the full walk in one call:

whisper verify --trustless signer-03ac74f2.c2pa.<tenant>.agents.whisper.online

 DNSSEC chain valid to the IANA root
 DANE-EE (TLSA 3 1 1) leaf matches the signer's key
 RDAP: registered under AS219419 · 2a04:2a01::/32
identity: VERIFIED, and our own API was never trusted

Or reach for the raw records directly: the same answer, from stock tools. The TLSA record is the pin: the 3 1 1 is a SHA-256 of the signer cert's SubjectPublicKeyInfo, so a validator can match it against the key inside any manifest that signer produced:

# the DANE pin: the signer's key, published under a DNSSEC-signed name
dig +dnssec TLSA _443._tcp.signer-03ac74f2.c2pa.<tenant>.agents.whisper.online +short
3 1 1 9e1b5580f2a4c7e1e0b3…c8d21f  ; the SHA-256(SPKI) any validator pins to

# the public verify endpoint: evidence chain in JSON
curl -s https://whisper.online/verify-identity/2a04:2a01:c2a::51 | jq
{ "is_whisper_agent": true, "dane_ok": true, "jws_ok": true, "evidence": { /* … */ } }

# the address is the signer: forward-confirmed reverse DNS names it
dig -x 2a04:2a01:c2a::51 +short
signer-03ac74f2.c2pa.<tenant>.agents.whisper.online.

# the registry object: who holds the address, and under which allocation
curl -s https://whisper.online/ip/2a04:2a01:c2a::51 | jq

None of these calls Whisper as an authority: --trustless re-derives the proof against the public DNSSEC root, exactly as any resolver could. This is the second, DNS-anchored proof that complements the certificate a manifest already carries: a relying party outside your community can confirm the signer without any pre-provisioned anchor. See Verify an agent for the full keyless check and DANE & TLSA for the pin, byte for byte.

Revoke a compromised signer, worldwide

A stolen signing key, a decommissioned press, a device whose secure element was found vulnerable: one call tears down the /128, its PTR, and its DANE pin everywhere at DNS-TTL speed:

CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:c2a::51'}})

# after the TTL: dig -x returns nothing, verify returns false
whisper kill --revoke 2a04:2a01:c2a::51

This is the revocation the provenance stack lacks at the identity layer. When a camera vendor's authenticity service was found vulnerable in 2025, it had to suspend the service and revoke its entire set of C2PA device certificates: every unit in the field, model-wide, because trust was pinned per-model, not per-unit. Per-signer identities derived from each device's own key, DNSSEC/DANE-anchored and individually revocable, turn that into a one-unit action at DNS-TTL: revoke the compromised signer and leave the rest of the fleet trusted. Compromise one signer and you've compromised that signer, not your whole imprint.

Short of a full revoke, the same control plane governs what each signer identity may reach: op:policy and op:firewall set a default-deny egress allow-list per identity: permit your TSA and your publishing endpoints, block everything else, by name, CIDR, or port. op:budget caps an identity's traffic with a kill-switch. It constrains who a signing box can talk to and be reached by, choking exfil and abuse, without an inline chokepoint.

And nothing is issued or torn down in the dark. Every mint and every revoke lands in a public, append-only RFC 6962 Merkle transparency log, Ed25519-signed and anchored to Bitcoin via OpenTimestamps: a non-repudiable issuance-and-revocation trail an EU AI Act auditor, a court, or a licensing partner can replay. Honest status: it is tamper-evident, signed, and Bitcoin-anchored today, but not yet independently witnessed. It speaks the C2SP tlog-witness protocol so an external witness can co-sign.

Who verified: the loop C2PA structurally can't close

This is the capability nobody else in provenance can offer. Because a C2PA validator builds the entire chain from certificates carried inside the manifest, verification generates no network call, which is elegant, and which also means the signer is blind: once content is out, they never learn who checked it. Anchor the signer in DNS/DANE instead, and the act of verifying (resolving the identity's name, matching the TLSA record, querying RDAP) becomes traffic against Whisper's own authoritative DNS and RDAP. op:lookups hands that back to the owner.

each verifier resolves + validates the signer identity, and that is observable Your signed asset DANE-anchored signer identity resolves in DNS Newsroom / platform UGC / search ingest Fact-check desk Whisper DNS + RDAP PTR / AAAA / TLSA + RDAP /ip accesses the resolutions, captured op:lookups who verified your content where · how often impersonation early-warning C2PA verify needs no network call → the signer is normally write-only-blind. A DNS/DANE anchor is what makes verification observable.
Because a C2PA validator builds the whole chain from certs carried in the manifest, verification is normally a silent, write-only event. The signer never learns who checked their content. Anchor the signer in DNS/DANE and every verifier's resolution becomes a lookup Whisper can attribute. op:lookups is the "who verified my content, where, how often" loop C2PA can't close: a reconnaissance and impersonation tripwire, and a first-party analytics stream.
# who resolved or RDAP-queried this signer identity: the owner-facing companion to op:logs
curl -s https://whisper.online/ip/2a04:2a01:c2a::51/lookups | jq

# or over the control plane, with your key
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:c2a::51'}})

It reads two ways: as a reconnaissance signal (an unusual burst of resolutions against a signer whose content isn't public yet, or against a signer being impersonated, is an early warning before the abuse spreads) and as verification analytics: which platforms and partners actually check your content, where it travelled, and where credentials were being validated (or conspicuously weren't). Where op:logs shows a signing box's own outbound activity, op:lookups shows the interest in it. Pair it with signed outputs so an AI tool or agent signs its own C2PA claim under a Whisper-anchored identity, and both the provenance and the verification trail become yours. (Whisper anchors the signer identity; you produce the C2PA/CAWG signature with your existing tooling. A turnkey Whisper-native signing helper is on the roadmap, below.)

Attribution: name whoever spoofed your identity

Identity stops the next forgery; the graph names the operator behind the abuse already in your logs. C2PA's own security model acknowledges identity-assertion spoofing: lift a valid identity assertion from one of your assets, embed it in a new asset, and falsely attribute new content to your brand. Whisper's attribution names the infrastructure behind that campaign. It survives IP rotation because it fingerprints the operator and the tooling, not the ephemeral egress IP. Run it as read-only Cypher over the same public API with your key (there is no CLI subcommand for this; it is the graph API directly):

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H 'content-type: application/json' \
  -d '{"query":"CALL whisper.identify(\"34.90.x.x\")"}'
# operator fingerprinted across AWS / GCP / Azure; residential swarm collapsed by JA3/JA4

The read-only verbs, identify, origins, walk, variants, history, each return a reproducible, replayable JSON evidence chain your trust-and-safety desk, a fact-checker, and an ICC/OSINT evidentiary dossier can replay. More in Graph & cognition.

What ships today, and what's on the roadmap

We label these honestly so you can plan against them, and we are especially careful about signing: Whisper anchors the signer identity; producing the C2PA/CAWG signature itself is your existing tooling's job today.

Shipped & liveOn the roadmap
Signer /128 from the signer's key + device_id (C2PA signer-cert serial or a CAWG identity): DNSSEC + DANE-EE + RDAP; verify, revoke, lookups A first-class typed --signer-cert / --cawg CLI+API argument (provision via the control-plane call today)
Control-plane provision, verify, revoke, lookups (who-verified), firewall / budget / policy; the attribution graph and the Merkle transparency log over the public API A turnkey Whisper-native sign-outputs helper that emits the C2PA/CAWG signature for you (today you sign with your own C2PA tooling; Whisper anchors the signer)
The Splunk, Microsoft Sentinel and OpenCTI connectors (signed, replayable JSON → CEF / ECS fields) STIX 2.1 over TAXII export; a formal DANE-anchor C2PA conformance submission (today the DANE anchor is surfaced via CAWG as a complementary identity ecosystem, not an approved C2PA Trust-List anchor)

The integration guides below describe proposed integrations at the C2PA/CAWG and IP boundary, designed to complement the stack you already run (the C2PA manifest, watermarking, in-camera signing), not endorsed by any vendor, and never named against a specific publisher, platform, or device maker as a breach victim.

The five Content guides

The content story, in depth. Each page is self-contained and copy-paste runnable.

The full technical library

Content rides on the same address-is-identity platform as every other agent on the network, so the whole shared library applies here unchanged, and every page has a clean Markdown twin at the same path + .md. Start with these; the rest is in the sidebar.