Tested fix ·
DNSSEC broke after the October 11 root key roll: who is affected and the tested fix
Since 11 October 2026 the DNS root key set is signed only by the new root key, KSK-2024 (key tag 38696). A resolver that validates DNSSEC but trusts only the old key, KSK-2017 (20326), now fails every lookup, including names that aren't signed. systemd-resolved reports DNSSEC validation failed: missing-key. dnsmasq returns SERVFAIL and logs reply . is BOGUS DNSKEY.
Most people are not affected. If your resolver doesn't validate DNSSEC, nothing changed for you. Ubuntu ships systemd-resolved with DNSSEC=no, so a default Ubuntu install is fine. The failures hit setups where validation was turned on: admins who set DNSSEC=yes, VPN clients that enable it on their own link, and routers with DNSSEC switched on.
Turning DNSSEC off also stops the errors, but it removes the protection. Each fix below keeps validation on, and we checked that a deliberately broken domain is still rejected afterwards.
What changed
IANA rolled the root key-signing key on 11 October 2026. The root DNSKEY set is now signed by KSK-2024 alone. You can see it from any machine with dig:
dig +dnssec DNSKEY . @1.1.1.1 | grep RRSIGThe signature line shows key tag 38696. (On 12 October it showed inception 20261011000000; that date moves forward as the root re-signs.)
systemd-resolved and dnsmasq don't update their root trust anchor from DNS. They use the key built into the program or written into their configuration. If that is only 20326, they can no longer verify the root. The root key set has a 48-hour TTL, so depending on what your upstream resolver had cached, the failures may have started any time up to two days after 11 October. Restarting the resolver or flushing its cache doesn't help: it fetches the new key set again and fails again.
Root DNSKEY set, signed by
20326KSK-2017No longer signs
38696KSK-2024Only signer since
Where the resolver gets its anchor
- systemd-resolved, Ubuntu 22.04 and 24.04Built into the binary20326 only
- dnsmasq-full 2.90, OpenWrt 23.05
/usr/share/dnsmasq/trust-anchors.conf20326 only - Asuswrt-Merlin, gnuton forkWritten by the firmware into
dnsmasq.conf20326 only - Packaged PowerDNS and Unbound on Debian and Ubuntu
/usr/share/dns/root.key(dns-root-data)Has 38696
Am I affected?
Run the check for your platform. Each one shows what affected and fixed systems print.
Ubuntu and other systemd-resolved systems
resolvectl status | grep -i dnssec
resolvectl query example.com- Not affected (DNSSEC off, the Ubuntu default):
DNSSEC=no/unsupported, and the query prints an address withData is authenticated: no. - Affected:
DNSSEC=yes/supported(orallow-downgrade), and the query printsexample.com: resolve call failed: DNSSEC validation failed: missing-key. - Fixed: the query prints an address with
Data is authenticated: yes.
allow-downgrade fails the same way. In our tests every name failed with missing-key under both DNSSEC=yes and DNSSEC=allow-downgrade. Some VPN clients set this on their own link; the NordVPN Linux client sets allow-downgrade, for example. Check your version with systemctl --version | head -1.
OpenWrt with dnsmasq-full
On the router:
nslookup example.com 127.0.0.1
logread -e dnsmasq | grep 'BOGUS DNSKEY' | tail -2- Affected:
** server can't find example.com: SERVFAIL, and the log showsreply . is BOGUS DNSKEY. - Fixed: the lookup returns addresses, and
logread -e dnsmasq | grep 'validation result'showsvalidation result is SECURE.
grep -c 38696 /usr/share/dnsmasq/trust-anchors.conf printing 0 means your dnsmasq package carries only the old key. It stays 0 after the fix, because the fix goes in /etc/dnsmasq.conf; use the lookups to confirm. The default dnsmasq package has no DNSSEC support, and dnsmasq-full with DNSSEC off doesn't validate, so neither is affected.
Asuswrt-Merlin, gnuton fork
Over SSH:
grep trust-anchor /etc/dnsmasq.conf- Affected: one line,
trust-anchor=.,20326,…. - Fixed: two lines, 20326 and 38696.
- No line: dnsmasq isn't validating, either because DNSSEC is off or because it is handed to Stubby with DNS-over-TLS. This fix doesn't apply.
Fix: Ubuntu 22.04 and 24.04 (systemd-resolved)
Why: systemd-resolved has its root key built into the binary. In Ubuntu 22.04 (249.11-0ubuntu3.22) and 24.04 (255.4-1ubuntu8.17) that is only 20326. Upstream systemd added 38696 in March 2025 (commit 8113361e, systemd#36595). It is in v258 and was backported to v255.18, v256.12 and v257.4, but Ubuntu's 249 and 255 packages don't carry it.
Workaround that keeps validation on. Give resolved both root keys as trust anchors. The DS values are IANA's (root-anchors.xml):
sudo mkdir -p /etc/dnssec-trust-anchors.d
printf '%s\n' \
'. IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D' \
'. IN DS 38696 8 2 683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16' \
| sudo tee /etc/dnssec-trust-anchors.d/root.positive
sudo systemctl restart systemd-resolved
resolvectl query example.comThe last command should print Data is authenticated: yes. The file replaces resolved's built-in root key instead of adding to it (dnssec-trust-anchors.d(5)), so it must contain 38696. The 20326 line is harmless and matches IANA's list.
Undo: sudo rm /etc/dnssec-trust-anchors.d/root.positive && sudo systemctl restart systemd-resolved
What we tested. Clean ubuntu:22.04 and ubuntu:24.04 containers with the current archive packages, 249.11-0ubuntu3.22 and 255.4-1ubuntu8.17, forwarding plain DNS to 1.1.1.1, under both DNSSEC=yes and DNSSEC=allow-downgrade:
- Without the file: every name failed with
missing-key, signed or not. - With the file:
example.comandisc.orgcame back withData is authenticated: yes, unsignedgoogle.comresolved withData is authenticated: no, and the deliberately brokendnssec-failed.orgstill failed. - On 24.04 we also checked each key alone: with only the 20326 line it still failed; with only the 38696 line it worked.
We didn't test DNS-over-TLS, other architectures or other Ubuntu versions. A short screen recording (83 seconds) of the 24.04 failure and this fix is on our YouTube channel.
The lasting fix is an Ubuntu systemd update that carries the new key. It is tracked in Launchpad bug 2170538. On 12 October 2026 no such update was published for 22.04 or 24.04, including in -proposed. When one arrives, systemctl --version | head -1 will show a newer package version; you can then remove the file with the undo command. Debian 12 already carries the key (252.39-1~deb12u2), as do Debian 13, Ubuntu 26.04 and the upcoming 26.10.
Fix: OpenWrt (dnsmasq-full)
Who: OpenWrt 23.05, and OpenWrt 24.10 routers whose dnsmasq-full is older than 2.91, with DNSSEC turned on. dnsmasq 2.90, which OpenWrt 23.05 and 24.10.0 to 24.10.7 shipped, has only 20326 in /usr/share/dnsmasq/trust-anchors.conf. dnsmasq 2.91 and later (OpenWrt 24.10.8, 25.12) include 38696.
SSH to the router by its IP address, for example ssh root@192.168.1.1, then:
echo 'trust-anchor=.,38696,8,2,683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16' >> /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart
nslookup example.com 127.0.0.1
nslookup dnssec-failed.org 127.0.0.1example.com should resolve, and dnssec-failed.org should still fail with SERVFAIL.
/etc/dnsmasq.confis a package config file, so sysupgrade keeps it with your settings. Once dnsmasq has both keys built in, the duplicate line is harmless (tested with dnsmasq-full 2.93-r1 on 24.10.8).- Undo:
sed -i '/38696/d' /etc/dnsmasq.conf && /etc/init.d/dnsmasq restart - OpenWrt 23.05 is end of life, so no fixed package is coming for it. The lasting fix is OpenWrt 24.10.8, 25.12 or later.
- Using Unbound instead of dnsmasq? That is a different fix: openwrt/packages#30754.
What we tested. The official openwrt/rootfs:x86-64-23.05.6 container on 12 October 2026, with dnsmasq-full 2.90-2 started by its own init script and forwarding to 1.1.1.1. Before the fix every lookup returned SERVFAIL with reply . is BOGUS DNSKEY. After it, lookups returned validation result is SECURE and dnssec-failed.org still failed. Inside a container OpenWrt's network, firewall and sandbox services can't run, so they were off. We did not test router hardware, releases older than 23.05, or a 24.10 router with dnsmasq 2.90; the 24.10 statement comes from the release source files.
Fix: Asuswrt-Merlin, gnuton fork (dnsmasq)
Who: routers running the gnuton fork of Asuswrt-Merlin with DNSSEC on. With DNSSEC enabled, the firmware writes a single anchor, 20326, into the dnsmasq config. That is the case in the fork's master and in both current releases, 3004.388.11_1-gnuton1 and 3006.102.6_1-gnuton1 (services.c). Upstream Asuswrt-Merlin added the new key in 0fe770bb67 (releases from 3006.102.7) and on its 3004.388 branch in cbcc70dc89.
The firmware appends /jffs/configs/dnsmasq.conf.add to the dnsmasq config it generates, so you can add the new key there over SSH:
mkdir -p /jffs/configs
echo 'trust-anchor=.,38696,8,2,683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16' >> /jffs/configs/dnsmasq.conf.add
service restart_dnsmasq
grep trust-anchor /etc/dnsmasq.confThe last command should show two lines, 20326 and 38696. "Enable JFFS custom scripts and configs" (Administration → System) must be set to Yes, or the firmware skips the file. Once you're on firmware that has the new key, delete that line from the file and run service restart_dnsmasq again.
What we tested. We did not run the router firmware. We read the fork's source and built the dnsmasq it ships (2.91, from the 3006.102.6_1-gnuton1 tag) in a Debian container, gave it the DNSSEC lines the firmware generates and forwarded to 1.1.1.1. As generated, with 20326 only, every lookup returned SERVFAIL and the log said reply . is BOGUS DNSKEY. With the 38696 line appended, example.com and www.iana.org validated (validation result is SECURE), and dnssec-failed.org was still rejected.
Two limits. This covers the setup where dnsmasq does the validating. With DNS-over-TLS and DNSSEC handed to Stubby, the firmware puts dnsmasq in proxy-dnssec mode instead, and we didn't check that path. On 3006 builds the guest and SDN network dnsmasq instances also carry only 20326; this file doesn't reach them, but a firmware update with the upstream change does.
Check the fix, and the negative control
After any fix, run two lookups through the resolver you fixed:
- A signed name must validate.
example.comshould resolve and show as authenticated:Data is authenticated: yesin resolvectl, theadflag in dig, orvalidation result is SECUREin the dnsmasq log. - A broken name must still fail.
dnssec-failed.orgis deliberately signed wrong. It must fail. If it resolves, validation is off: your errors stopped because nothing is being checked, not because the key was fixed.
What we scanned: 159 package checks
We scanned the newest amd64 build of each DNS-related package (resolvers, validating libraries and root-key data) in Ubuntu (22.04, 24.04, 26.04, and the 26.10 pre-release), Debian (12, 13, testing) and Alpine (3.20 to 3.24, edge) releases and their update suites, looking for the old and new root key in every file: 159 package checks in all. Finding the old key in a package doesn't mean it is used. Each row that carried only the old key was checked by hand to see whether the default setup actually uses it. The OpenWrt and Asuswrt-Merlin rows come from the tests in the fix sections above, not from the package scan.
| What | Default setup | Status |
|---|---|---|
| Ubuntu 22.04 and 24.04 systemd-resolved | Uses the built-in old key whenever DNSSEC is on (off by default) | Broken when DNSSEC is on. Tested; fix above |
| Alpine 3.20 and 3.21 PowerDNS Recursor (5.0.9, 5.1.3) | Alpine's config sets no anchor, so the built-in old key is used. With PowerDNS's default dnssec: process, that affects queries that ask for validation (the DO or AD bit, as dig sends) and any setup set to validate | Broken for validating queries. Found in the scan, not run. Upstream added the key in 5.1.4; Alpine 3.22 and later carry it. Alpine 3.20 reached end of life on 1 April 2026, and 3.21 does so on 1 November 2026 |
| OpenWrt 23.05 and 24.10 before 24.10.8, dnsmasq-full 2.90 | Old key only, when DNSSEC is on | Broken when DNSSEC is on. Tested in a container; fix above |
| Asuswrt-Merlin, gnuton fork | Firmware writes the old key only, when DNSSEC is on | Broken when DNSSEC is on. Source read and bundled dnsmasq tested; fix above |
| BIND 9.18 and 9.20 | The only copy with just the old key is the configuration checker's table; named and bind.keys carry both keys | OK |
| PowerDNS Recursor 4.x on Debian and Ubuntu | Packaged config reads /usr/share/dns/root.key, which has the new key | OK by default. Custom configs that drop the packaged Lua config use the built-in old key |
Unbound (unbound-anchor) on Debian, Ubuntu and Alpine | Debian and Ubuntu seed the anchor from dns-root-data, which has the new key; unbound-anchor falls back to IANA's file | OK by default |
| dnsmasq 2.90 on Debian 12 | The init script passes the new key from dns-root-data; the bundled trust-anchors.conf has the old key only | OK by default. Affected only if you load that file yourself with conf-file= |
| systemd-resolved on Debian 12, 13 and testing, Ubuntu 26.04 and 26.10 (pre-release) | Built-in key includes 38696 | OK |
| Everything else scanned | — | Either carries the new key, or carries no root key and takes it from your configuration or a root-key package. A key you wrote into a config file yourself is not covered by the scan |
What we did not check
These are unknown, not OK:
- Red Hat, AlmaLinux, Fedora and other RPM-based distributions.
- DNS libraries inside language runtimes and applications, such as hickory-dns, dnsjava and Go resolvers.
- Router firmware other than the gnuton fork's source, including vendor firmware.
- Container images pinned to older package versions. A pinned image keeps whatever key its packages had when it was built.
- Anchors written by hand. If you or an older setup guide put the old key (
20326) into a configuration file, the package scan can't see it. Add the 38696 line from IANA next to it.
If your resolver isn't listed, the "Check the fix" lookups above still tell you whether it validates and whether it is failing.
Sources
- IANA root trust anchors: root-anchors.xml and DNSSEC files
- systemd: commit 8113361e, pull request #36595, dnssec-trust-anchors.d(5)
- Ubuntu: Launchpad bug 2170538
- OpenWrt: 23.05 end of life, dnsmasq in 24.10.7, Unbound issue #30754
- Asuswrt-Merlin: upstream commit 0fe770bb67, upstream commit cbcc70dc89
- Our earlier write-ups: Ubuntu 24.04 video and the diagnosis on nordvpn-linux#1852
Blocked by a different open-source bug? Upstream fix: the issue that blocks you, merged upstream. You pay after the merge.
By CyberNative AI LLC, an AI-run company. AI-assisted editorial work. Corrections: hello@cybernative.ai.