Introduction
A race condition in BIND 9's asynchronous SIG(0) signature validation can be triggered during a query flood, causing the named process to crash with a segmentation fault. For any organization relying on BIND 9 for authoritative or recursive DNS, this vulnerability (scored CVSS 7.5) introduces a remotely exploitable denial of service condition that requires no authentication, no user interaction, and no special configuration to reach.
Technical Information
Root Cause: Raw Pointer in a Concurrent Context
The vulnerability lives in lib/dns/resolver.c, specifically in the function rctx_respinit(). When BIND receives an incoming DNS response containing a SIG(0) signature, it offloads the cryptographic verification (for example, P-384 ECDSA) to an asynchronous worker thread via dns_message_checksig_async(). This async operation takes roughly 3 ms to complete. During that window, a flood of queries can exhaust the recursive-clients limit. When the limit is hit, BIND walks the call chain fctx_shutdown() → fctx_cancelqueries() → resquery_detach(), which drops the reference count on the resquery_t object to zero and frees it.
The core problem is that the response context (rctx) held a raw pointer to this query object without bumping its reference count:
// VULNERABLE CODE in rctx_respinit() *rctx = (respctx_t){ .result = result, .query = query, /* raw pointer — no refcount bump */ .fctx = fctx, ... };
When the async signature check callback fires and invokes resquery_response_continue(), it dereferences rctx->query. If the query object has already been freed by the concurrent cancellation path, this becomes a dangling pointer dereference: a classic use after free (CWE-416) caused by a race condition (CWE-362).
On most systems, this manifests as a segmentation fault that crashes the named process. The vendor notes that if the memory from the discarded message has not been reused or reclaimed, the validation might proceed normally, but the behavior is formally undefined. ISC also states that arbitrary code execution from this improper data read is unlikely.
Attack Flow
An attacker does not need any special privileges or prior access. The exploitation sequence, based on the vulnerability mechanics described in the advisory, would look like this:
- The attacker sends DNS messages signed with SIG(0) to a target BIND 9 resolver or authoritative server.
- Simultaneously, the attacker (or a separate botnet) floods the same server with a high volume of recursive queries to push the server toward its
recursive-clientslimit. - When the limit is reached, BIND begins discarding in flight queries. If a SIG(0) signed message is among those discarded while its async cryptographic verification is still running, the race condition is triggered.
- The async callback dereferences the freed
resquery_tobject, causing a segmentation fault and crashing thenamedprocess.
Because the trigger condition closely resembles a standard query flood, this vulnerability could be folded into existing DDoS tooling with minimal effort.
Patch Information
ISC publicly disclosed CVE-2026-5947 on May 20, 2026 and simultaneously released patched versions of BIND 9. The fix is available in BIND 9.20.23, BIND 9.21.22, and BIND Supported Preview Edition 9.20.23-S1. The closing commits are tracked in the ISC GitLab repository under issue GL #5819, with commit 9831f418 landing on the v9.20 branch and commit f6d19314 on the development branch.
The fix follows the existing ownership pattern already used for rctx->mctx (which uses isc_mem_attach()). The patch replaces the raw pointer assignment with a proper reference counted attach, and adds corresponding detach calls at every exit point where rctx is freed. The researcher Naoki Wakamatsu proposed essentially the same solution in the original vulnerability report. Here is the core of the diff:
--- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ rctx_respinit() *rctx = (respctx_t){ .result = result, - .query = query, .fctx = fctx, .broken_type = badns_response, .retryopts = query->options }; + /* Attach so rctx holds a counted reference; detach when rctx is freed. */ + resquery_attach(query, &rctx->query); @@ resquery_response() cleanup: + resquery_detach(&rctx->query); isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx)); @@ resquery_response_continue() cleanup: + resquery_detach(&rctx->query); isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
By calling resquery_attach(), the reference count on the resquery_t object is incremented, ensuring that even if fctx_cancelqueries() runs concurrently and drops its own reference, the object cannot be freed while the async SIG(0) verification is still in flight. The matching resquery_detach() at the cleanup label brings the refcount back down once the response context is done. This completely closes the race window.
The BIND 9.18.x ESV branch is not affected because the async SIG(0) verification path (dns_message_checksig_async()) was introduced in commit 70ff4a3f on March 6, 2024, and first shipped in v9.20.0.
No workarounds are available. Administrators running any affected version must upgrade to the corresponding patched release.
Affected Systems and Versions
The following table summarizes affected, unaffected, and fixed versions:
| Category | Versions |
|---|---|
| Affected | 9.20.0 through 9.20.22 |
| Affected | 9.21.0 through 9.21.21 |
| Affected | 9.20.9-S1 through 9.20.22-S1 (Supported Preview Edition) |
| Not Affected | 9.18.28 through 9.18.49 |
| Not Affected | 9.18.28-S1 through 9.18.49-S1 |
| Fixed | 9.20.23, 9.21.22, 9.20.23-S1 |
Both authoritative servers and resolvers running affected versions are vulnerable. The vulnerability is triggered when the server processes SIG(0) signed DNS messages while under query flood conditions that push the recursive-clients limit.
Organizations running the 9.18.x branch do not need to apply emergency patches for this specific CVE, though they should note that 9.18.x is approaching its end of life in Q2 2026.



