CVE-2026-42923
Description
NLnet Labs Unbound up to and including version 1.25.0 has a vulnerability in the DNSSEC validator where the code path to consult the negative cache for DS records does not take into account the limit on NSEC3 hash calculations introduced in 1.19.1. This leads to degradation of service during the attack. An adversary that controls a DNSSEC signed zone can exploit this by signing NSEC3 records with acceptably high iterations for child delegations and querying a vulnerable Unbound. Unbound will keep performing the allowed hash calculations on the NSEC3 records and will not limit the work by the mitigation introduced in 1.19.1. As a side effect, a global lock for the negative cache will be held for the duration of the hashing, blocking other threads that need to consult the negative cache. Coordinated attacks could raise the vulnerability to denial of service. Unbound 1.25.1 contains a patch with a fix to bound the vulnerable code path with the existing limit for NSEC3 hash calculations.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Unbound DNSSEC validator's negative cache DS record code path ignores NSEC3 hash limit, causing CPU and lock contention that can lead to denial of service.
Vulnerability
NLnet Labs Unbound up to and including version 1.25.0 contains a vulnerability in the DNSSEC validator. When the validator consults the negative cache for DS records, it does not apply the limit on NSEC3 hash calculations that was introduced in version 1.19.1. This allows an attacker to trigger excessive hashing [1].
Exploitation
An adversary that controls a DNSSEC signed zone can exploit this by signing NSEC3 records with acceptably high iterations for child delegations and querying a vulnerable Unbound resolver. Unbound will perform the allowed hash calculations on the NSEC3 records without the work-limiting mitigation from 1.19.1. As a side effect, a global lock for the negative cache is held during the hashing, blocking other threads that need to consult the negative cache [1].
Impact
The attack causes degradation of service due to excessive CPU consumption and lock contention. Coordinated attacks can raise the impact to a full denial of service, preventing legitimate resolution [1].
Mitigation
Unbound 1.25.1 contains a patch that bounds the vulnerable code path with the existing limit for NSEC3 hash calculations. Administrators should upgrade to version 1.25.1 or apply the patch manually from the vendor advisory [1].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
1c343fff3a4de- Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
4 files changed · +36 −6
doc/Changelog+3 −0 modified@@ -16,6 +16,9 @@ - Fix CVE-2026-42534, Jostle logic bypass degrades resolution performance. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix CVE-2026-42923, Degradation of service with unbounded NSEC3 + hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for + the report. 23 April 2026: Wouter - Merge #1441: Fix buffer overrun in
validator/val_neg.c+27 −1 modified@@ -62,6 +62,13 @@ #include "sldns/rrdef.h" #include "sldns/sbuffer.h" +/** + * The maximum salt length that the negative cache is willing to use. + * Larger salt increases the computation time, while recommendations are + * for zero salt length for zones. + */ +#define MAX_SALT_LENGTH 64 + int val_neg_data_compare(const void* a, const void* b) { struct val_neg_data* x = (struct val_neg_data*)a; @@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cache* neg, (slen != 0 && zone->nsec3_salt && s && memcmp(zone->nsec3_salt, s, slen) != 0))) { - if(slen > 0) { + if(slen > MAX_SALT_LENGTH) { + /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large + * salts inflate per-hash block count. Decline to cache. */ + return; + } else if(slen > 0) { uint8_t* sa = memdup(s, slen); if(sa) { free(zone->nsec3_salt); @@ -1165,6 +1176,15 @@ neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len, uint8_t hashce[NSEC3_SHA_LEN]; uint8_t b32[257]; size_t celen, b32len; + int hashmax = MAX_NSEC3_CALCULATIONS; + if(qlabs > hashmax) { + /* strip leading labels so the walk costs at most + * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */ + while(qlabs > hashmax) { + dname_remove_label(&qname, &qname_len); + qlabs--; + } + } *nclen = 0; while(qlabs > 0) { @@ -1265,6 +1285,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len, if(!zone->nsec3_hash) return NULL; /* not nsec3 zone */ + if(!topname && qlabs > zone->labs + 1) + return NULL; /* iterator caller; opt-out proof would be discarded + * at the !topname check below anyway. + * The qlabs check allows the exact-match for + * the one-label-below-zone case. */ + if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf, hashnc, &nclen))) { return NULL;
validator/val_nsec3.c+0 −5 modified@@ -59,11 +59,6 @@ #include "sldns/sbuffer.h" #include "util/config_file.h" -/** - * Max number of NSEC3 calculations at once, suspend query for later. - * 8 is low enough and allows for cases where multiple proofs are needed. - */ -#define MAX_NSEC3_CALCULATIONS 8 /** * When all allowed NSEC3 calculations at once resulted in error treat as * bogus. NSEC3 hash errors are not cached and this helps breaks loops with
validator/val_nsec3.h+6 −0 modified@@ -98,6 +98,12 @@ struct sldns_buffer; /** The SHA1 hash algorithm for NSEC3 */ #define NSEC3_HASH_SHA1 0x01 +/** + * Max number of NSEC3 calculations at once, suspend query for later. + * 8 is low enough and allows for cases where multiple proofs are needed. + */ +#define MAX_NSEC3_CALCULATIONS 8 + /** * Cache table for NSEC3 hashes. * It keeps a *pointer* to the region its items are allocated.
Vulnerability mechanics
Root cause
"The negative cache code path for DS-record NSEC3 proofs does not enforce the existing limit on NSEC3 hash calculations, allowing an unbounded number of hash computations per query."
Attack vector
An attacker who controls a DNSSEC-signed zone signs NSEC3 records with acceptably high iterations for child delegations. When a vulnerable Unbound resolver queries for DS records under that zone, the negative cache code path in `neg_nsec3_proof_ds` and `neg_find_nsec3_ce` [patch_id=792205] performs NSEC3 hash calculations without applying the `MAX_NSEC3_CALCULATIONS` limit that was introduced in version 1.19.1 for other code paths. The attacker can craft NSEC3 records with a large number of labels or a long salt to inflate the per-hash computation cost. Because a global lock for the negative cache is held during hashing, other threads are blocked, leading to degradation of service. Coordinated queries from multiple attackers can escalate this into a denial-of-service condition [CWE-407].
Affected code
The vulnerability is in `validator/val_neg.c` [patch_id=792205], specifically in the functions `neg_find_nsec3_ce` (the label-walking loop that computes NSEC3 hashes) and `neg_nsec3_proof_ds` (the DS-proof entry point that calls it). The code path lacks the `MAX_NSEC3_CALCULATIONS` bound that was already present in `validator/val_nsec3.c` for other NSEC3 processing. The `MAX_NSEC3_CALCULATIONS` constant was previously defined only in `val_nsec3.c` and was not accessible to the negative cache code.
What the fix does
The patch applies three changes to `validator/val_neg.c` [patch_id=792205]. First, a `MAX_SALT_LENGTH` of 64 bytes is introduced; if the NSEC3 salt exceeds this length, the data is not cached, preventing attackers from inflating per-hash block count with oversized salts per RFC 9276. Second, in `neg_find_nsec3_ce`, a `hashmax` variable set to `MAX_NSEC3_CALCULATIONS` (8) is added; when the query label count exceeds this limit, leading labels are stripped so that at most 8 hash calculations are performed, mirroring the existing guard in `val_nsec3.c`. Third, in `neg_nsec3_proof_ds`, an early return is added for non-zone-top queries with more than `zone->labs + 1` labels, since such proofs would be discarded anyway. The `MAX_NSEC3_CALCULATIONS` definition is moved from `val_nsec3.c` to `val_nsec3.h` so it can be shared by both validator and negative-cache code.
Preconditions
- networkAttacker must be able to send DNS queries to a vulnerable Unbound resolver.
- inputAttacker must control a DNSSEC-signed zone and be able to serve NSEC3 records with acceptably high iterations and/or long salt values for child delegations.
Generated on May 20, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1- www.nlnetlabs.nl/downloads/unbound/CVE-2026-42923.txtnvdMitigationVendor Advisory
News mentions
0No linked articles in our index yet.