The KSK rollover won't break on 11 Oct. Your redeploy might.
A resolver that trusts only KSK-2017 does not fail at the root KSK rollover on 11 October 2026. It fails when it next fetches the root key set, and a container recreated from a stale image after that date fails on its first query. Tested on Unbound and BIND.A validating resolver that trusts only KSK-2017 will not break at the moment of the root KSK rollover on 11 October 2026. It breaks the first time it has to fetch the root key set again, and for a container, appliance, or VM recreated from a stale image after that date, that moment is its very first query, unless something refreshes the anchor at start. The incident date is your next redeploy, which can be weeks later, when nobody connects it to the rollover.
This post is about the recreated ones. The delayed failure on long-running resolvers is already well documented: ICANN's "What to Expect During the Root KSK Rollover" guide (27 July 2026) explains the 48-hour cache window in detail. What it does not walk through is what happens to a resolver whose trust-anchor state is thrown away on every restart, and which images still ship the old key today.
What the root KSK rollover changes on 11 October
The root zone has published two key-signing keys since January 2025: KSK-2017 (key tag 20326) and KSK-2024 (key tag 38696). Until the rollover, only KSK-2017 signs the root DNSKEY set. This is the live answer from a.root-servers.net, captured 4 October 2026 at 22:31 UTC, with the base64 key material replaced by ...:
$ dig . DNSKEY +dnssec +multi @a.root-servers.net
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33502
. 172800 IN DNSKEY 256 3 8 ( ... ) ; ZSK; alg = RSASHA256 ; key id = 8763
. 172800 IN DNSKEY 256 3 8 ( ... ) ; ZSK; alg = RSASHA256 ; key id = 57780
. 172800 IN DNSKEY 257 3 8 ( ... ) ; KSK; alg = RSASHA256 ; key id = 20326
. 172800 IN DNSKEY 257 3 8 ( ... ) ; KSK; alg = RSASHA256 ; key id = 38696
. 172800 IN RRSIG DNSKEY 8 0 172800 (
20261022000000 20261001000000 20326 .
... )One RRSIG, from 20326. After the rollover the key set is signed by KSK-2024 instead (ICANN guide, section 1.1). A resolver whose only trust anchor is 20326 can still see that key in the DNSKEY set, but no signature from it, so it cannot validate the root, and with it, nothing below the root.
The TTL on that set is 172800 seconds, 48 hours. That number is where the delay comes from: a resolver that validated the key set shortly before the switch keeps using the cached, already-validated copy until it expires. Our post on why DNS propagation is really cache expiry covers the general mechanism; ICANN's guide adds that resolvers with a max-TTL cap see the change sooner, and an idle single-user resolver can see it hours or days later.
Why a recreated resolver fails immediately, with no 48-hour window
The 48-hour grace only exists for a resolver that already has a validated key set in cache. A freshly started resolver has an empty cache. After 11 October its first lookup fetches a root DNSKEY set signed only by 38696, checks it against whatever anchor it booted with, and if that anchor is KSK-2017 only, every answer is bogus from the first query.
RFC 5011 automatic trust-anchor updates do not rescue this case. RFC 5011 section 2.4.1 sets an add hold-down of 30 days: a new key must be seen in validly signed DNSKEY sets for 30 days before it is trusted. Signed by what? By a key the resolver already trusts. Once KSK-2017 stops signing, a KSK-2017-only resolver has no way to start that clock.
We tested what a stale seed looks like today. Unbound 1.25.2 in alpine:3.22, with auto-trust-anchor-file seeded with only the KSK-2017 DS record, one query, then the file read back (key lines only, base64 shortened):
. 86400 IN DNSKEY 257 3 8 AwEAAa96... ;{id = 38696 (ksk), size = 2048b} ;;state=1 [ ADDPEND ] ;;count=1 ;;lastchange=1791153159 ;;Sun Oct 4 22:32:39 2026
. 86400 IN DNSKEY 257 3 8 AwEAAaz/... ;{id = 20326 (ksk), size = 2048b} ;;state=2 [ VALID ] ;;count=0 ;;lastchange=1791153159 ;;Sun Oct 4 22:32:39 2026KSK-2024 is seen and parked in ADDPEND. Thirty days from 4 October is 3 November, three weeks after the rollover. Any resolver that bootstrapped from a KSK-2017-only seed later than about 11 September 2026 will not trust KSK-2024 in time, even though it is running RFC 5011 correctly.
Put together, the failure time for a stale-seeded resolver depends on its history, not on the calendar:
- Started from the stale seed before about 11 September, kept running, and kept its state file: it has accepted KSK-2024 through RFC 5011 and is fine.
- Started from the stale seed after about 11 September: KSK-2024 is still in ADDPEND on 11 October. It fails when its cached key set expires, inside the 48-hour window ICANN describes.
- State file lives in the container layer (no volume): every recreate re-reads the stale seed and restarts the 30-day clock, so the good state from the first bullet is lost on the next deploy.
- Recreated after 11 October from the stale seed: fails on the first query, with no grace period at all.
Our opinion: the bug here is not the rollover. It is shipping a validating resolver whose trust anchor comes from the image and whose RFC 5011 state does not survive a restart. The rollover is the first event in eight years that exposes it.
The exception: unbound-anchor with HTTPS egress
unbound-anchor is the one tool in this list that can self-heal. Its manual page says it fetches the trust anchor with the RFC 7958 method (root-anchors.xml over HTTPS) when the regular RFC 5011 update fails to bring it up to date. We cannot reproduce the post-rollover root zone yet, so we tested the mirror image: an anchor file holding only 38696, which today matches no signature, the same position a KSK-2017-only file will be in after 11 October.
$ unbound-anchor -a c2.key -v
c2.key has content
no last_success probe time in anchor file
using builtin certificate
fetched root-anchors/root-anchors.xml (1861 bytes)
fetched root-anchors/root-anchors.p7s (2523 bytes)
the PKCS7 signature verified
XML was parsed successfully, 2 keys
success: the anchor has been updated using the certOutput trimmed (connection lines removed). The rewritten file held DS records for both 20326 and 38696. The same tool run today against a 20326-only file printed success: the anchor is ok and left 38696 in ADDPEND, because the stale anchor still validates before the switch. So unbound-anchor covers you after 11 October only if your entrypoint actually runs it before Unbound starts, and only if the container can reach data.iana.org over HTTPS. An egress policy that allows DNS but blocks outbound 443 removes the safety net.
Where KSK-2017-only anchors still ship
Every cell below was checked against the package contents or the source tree at that tag, not against release notes. "KSK-2017 only" means the shipped anchor file or built-in key contains 20326 and not 38696.
| Component | Checked, KSK-2017 only | Checked, includes KSK-2024 |
|---|---|---|
Alpine dnssec-root (default Unbound trust-anchor-file) |
20190225-r2, the current package in Alpine 3.18, 3.19, 3.20 and 3.21 | 20250524-r0 (Alpine 3.22) |
Debian bullseye dns-root-data |
2024041801~deb11u1 | 2024071801~deb11u1, first seen in debian-security on 23 June 2025 |
Debian bookworm dns-root-data |
not checked | 2024071801~deb12u1, first seen 11 January 2025 |
Unbound unbound-anchor built-in anchor |
1.20.0 | 1.21.0 |
BIND built-in bind.keys |
9.18.31, 9.20.3 | 9.18.32, 9.20.4 |
| systemd-resolved built-in anchor | v257 | v257.9, v258 |
Some rows need context.
Alpine 3.21 is still a supported release (end of support 1 November 2026 per Alpine's releases page), and installing Unbound on it today gives you a static anchor with only KSK-2017:
$ docker run --rm alpine:3.21 sh -c 'apk add --no-cache unbound >/dev/null; cat /etc/alpine-release; apk info -v 2>/dev/null | grep dnssec-root; grep -E "^\s*trust-anchor-file" /etc/unbound/unbound.conf; cut -c1-48 /usr/share/dnssec-root/trusted-key.key'
3.21.8
dnssec-root-20190225-r2
trust-anchor-file: "/usr/share/dnssec-root/trusted-key.key"
. IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSThat key is KSK-2017 (compare the PublicKey for key tag 20326 in IANA's root-anchors.xml). A trust-anchor-file is static, so there is no RFC 5011 path at all. This is the case where a long-running instance also fails within the 48-hour window, and every restart after that fails at once. Alpine 3.22 ships both keys.
BIND with dnssec-validation auto uses its built-in key only to initialise the managed-keys database. The BIND 9 reference manual is blunt about the consequence: a running server rolls to the new key, but "newly installed servers being run for the first time will need to be on a recent-enough version of BIND to have been built with the current key." A container whose managed-keys.bind is created in the container's writable layer, with no volume, is a newly installed server after every recreate.
systemd-resolved does not do RFC 5011 at all. Its dnssec-trust-anchors.d manual page says it "will not update its trust anchor database from DNS servers automatically" and recommends updating the resolver software or adding trust anchor files. If you set DNSSEC=yes, a systemd older than v257.9 (or a distro build without the backport) has no way to learn KSK-2024 by itself.
Debian's own service wiring is worth knowing too. On bookworm (unbound 1.17.1-2+deb12u4), unbound.service runs unbound-helper root_trust_anchor_update as ExecStartPre, which copies /usr/share/dns/root.key over /var/lib/unbound/root.key when the packaged file is newer. It does not run unbound-anchor. A container that starts unbound -d directly skips that step entirely.
What a resolver without KSK-2024 returns
You can see the post-rollover failure today by running the mirror image of the problem: a resolver that trusts only KSK-2024, which right now signs nothing. Same Unbound 1.25.2 in alpine:3.22, static anchor with only the 38696 DS record, queried with dig (output filtered to the status and EDE lines):
=== cloudflare.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12391
; EDE: 6 (DNSSEC Bogus): (validation failure <cloudflare.com. A IN>: signature for expected key and algorithm missing from 170.247.170.2 for trust anchor . while building chain of trust)
=== google.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 8714
; EDE: 6 (DNSSEC Bogus): (validation failure <google.com. A IN>: key for validation . is marked as invalid because of a previous signature for expected key and algorithm missing)
=== amazon.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 30499
; EDE: 6 (DNSSEC Bogus): (validation failure <amazon.com. A IN>: key for validation . is marked as invalid because of a previous signature for expected key and algorithm missing)
=== +cd google.com
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4432The same strings land in the Unbound log as info: validation failure <...> lines. A control run with a KSK-2017-only anchor returned NOERROR for the same names. EDE: 6 is the "DNSSEC Bogus" code from RFC 8914, and it is the string to grep for if your clients log extended errors.
Unsigned names failed too. google.com and amazon.com have no DS record in .com (dig google.com DS +short returned nothing when we checked), so they are not DNSSEC-signed. They still came back SERVFAIL, because proving that a name is unsigned needs a validated chain from the root, and the root itself was bogus. BIND's delv 9.20.29 with a 38696-only static-ds showed the same pattern for google.com:
;; validating ./DNSKEY: no valid signature found (DS)
;; no valid RRSIG resolving './DNSKEY/IN': 1.1.1.1#53
;; broken trust chain resolving 'com/DS/IN': 1.1.1.1#53
;; broken trust chain resolving 'google.com/A/IN': 1.1.1.1#53That is the tested behaviour of Unbound 1.25.2 and delv 9.20.29, not a law for every validator. It does contradict Netdata's BIND trust-anchor guide, which lists "Unsigned domains resolve normally" as a symptom of a stale anchor and names google.com among the signed domains. Do not plan on unsigned names keeping your service half-alive.
The +cd check is the fastest discriminator. If a name fails normally but resolves with checking disabled, the problem is validation, and if it fails for every name including unsigned ones, suspect the root anchor before any individual zone. Zone-side breakage, where one domain's own DS or signatures are wrong, looks different; our guide to diagnosing DNSSEC SERVFAIL covers that side.
Why your uptime monitor will stay green
An outside-in uptime check resolves your hostname with the monitoring service's resolver, not yours. If the stale anchor sits in your own egress resolver, inbound traffic keeps working and every external check passes. What breaks is everything your servers look up: payment APIs, webhooks, SMTP relays, object storage, OAuth providers. In application logs that reads as a wave of third-party timeouts and "could not resolve host" errors, which points everyone at the vendors.
ICANN's guide adds that failures are not uniform: two clients using different resolvers get different results, and a client spread across prepared and unprepared resolvers fails intermittently. A fleet where half the pods were recreated after 11 October and half were not will look exactly like that.
Our own product does not close this gap, and we would rather say so. WebPixie's DNS monitoring validates your zone's DNSSEC chain (DNSKEY, DS, RRSIG, NSEC) from the outside every day. That catches a broken chain on your domain. A stale root anchor inside your own resolver is a different layer: your zone is fine, so that check stays green. The signal has to come from inside your network.
Three inside-out checks cover it:
- A scheduled probe from each environment that runs
dig +dnssec . DNSKEYagainst the resolver your apps actually use and alerts on SERVFAIL. In our 38696-only test above, that query returned SERVFAIL with the same EDE 6, so a recreated stale resolver fails this on its first run after 11 October. - A log alert on Unbound's
validation failurelines, or on a jump innum.answer.bogusfromunbound-control stats(answers that failed validation and went out as SERVFAIL). - A post-deploy smoke test that resolves one external name from inside the new container, not from the CI runner.
Checks to run before 11 October
Find every validating resolver you ship, then check which keys it actually trusts, in the state it will have after a restart, not the state of the instance that has been up since spring.
- Search images and config for the anchor files:
trust-anchor-file,auto-trust-anchor-file,trust-anchors,managed-keys,dnssec-trust-anchors.d, andDNSSEC=yesinresolved.conf. - For Unbound with RFC 5011, look for 38696 in
VALIDstate, notADDPEND, in yourauto-trust-anchor-file(on Debian:grep 'id = 38696' /var/lib/unbound/root.key). For a statictrust-anchor-file, check the file contains both keys. - For BIND,
rndc managed-keys statuslists the keys in the managed-keys database. Then check the BIND version baked into the image against the table above, because that is what a fresh start uses. - Build the image from scratch and run the check inside a brand-new container. A long-lived instance can pass while the image fails.
- Put RFC 5011 state on a persistent volume the resolver user can write, or replace the seed with a current anchor file from IANA at build time. If you rely on
unbound-anchor, make sure the entrypoint runs it and outbound HTTPS todata.iana.orgis allowed.
If something breaks after 11 October anyway, ICANN's recovery order is to stop the bleeding first, by temporarily disabling validation or setting a negative trust anchor for the root (RFC 7646), then install KSK-2024 and turn validation back on. Rebuild the image afterwards, or the next deploy brings the failure straight back.
This will not be the last time. ICANN expects the next root rollover, estimated to conclude in 2029, to also change the algorithm to ECDSA, which adds a second way for old validators to fail (our post on post-quantum DNSSEC looks at what happens when validators meet an algorithm they cannot handle). Images that pin a trust anchor at build time will hit the same redeploy trap again unless the anchor gets a refresh path now.