How this works
- Your browser lists the zones that could hold the name. For
www.example.com that's www.example.com, example.com, com and the root. It asks for each one's SOA record, which only a zone's apex has, and its DS record, which a parent zone publishes for each signed child. The record you picked is asked for at the same time.
- For each zone it finds, it asks for the zone's public keys (DNSKEY) and NSEC3 settings (NSEC3PARAM). Every query sets the DNSSEC OK bit (RFC 3225), so signatures (RRSIG) and proofs that names don't exist (NSEC, NSEC3) come back too.
- Browsers can't send DNS packets, so the queries go in batches to
abbott.cloud/api/dns, which relays them unchanged to the resolver you chose, using DNS over HTTPS (RFC 8484). If the resolver refuses an answer as bogus (SERVFAIL), the page asks again with Checking Disabled (RFC 4035 §3.2.2) to see the data itself.
- Everything else happens on your device. Starting from the root zone's trust anchors published by IANA (KSK-2017, key tag 20326, and KSK-2024, key tag 38696), the page recomputes each DS digest from the child zone's key (RFC 4034 §5.1.4). It verifies each signature with your browser's Web Crypto, over the records' canonical form (RFC 4034 §6). A zone counts as unsigned only if its parent's signed NSEC or NSEC3 records prove there's no DS record for it (RFC 4035 §5.2).
- Finally it checks the record you asked for with its zone's keys, or the signed proof that it doesn't exist (RFC 4035 §5.4, RFC 5155 §8). An answer made from a wildcard also needs proof that no closer name exists (RFC 4035 §5.3.4), and a parent's NSEC or NSEC3 record at a delegation only proves there's no DS record (RFC 6840 §4.1).
What's kept: nothing. The name you check goes in the page's address so you can share the result, but it isn't stored. The resolver sees the queries arrive from Cloudflare's network, not from your IP address.
Algorithms: RSASHA1, RSASHA256, RSASHA512, ECDSA P-256 and P-384, and Ed25519. Ed448 works if your browser supports it. RSAMD5, DSA and GOST aren't checked, in line with RFC 8624.
Limitations: the page sees DNS through a public resolver's cache rather than each authoritative nameserver, so it can't spot one nameserver that's out of step with the others, and recent changes can take up to a record's TTL to show. An alias (CNAME or DNAME) is checked up to the alias record, so check its target separately. If the target doesn't exist and is in the same zone, the page checks the proof of that too. NSEC3 records with more than 150 extra iterations aren't checked, because widely used validators treat them as unsigned (RFC 9276 §3.2). To keep the resolvers' services fair for everyone, abbott.cloud limits how many lookups each visitor can make a minute.
Test hook: when the page loads, it reads replacement root anchors from window.__DNSSEC_TRUST_ANCHORS__ if they're there. This is used only by this site's automated tests, whose simulated zones can't be signed by the real root key. Results always say so when it's in use.
Code: dnssec.js (this page), lib/dnssec.js (validation), dnswire.js (packet encoding and decoding), net.js (requests).