GHSA-2WPX-QPW2-G5H5
Vulnerability from github – Published: 2026-04-28 22:40 – Updated: 2026-05-08 15:27Summary
CoreDNS' DNS-over-QUIC (DoQ) server can be driven into large goroutine and memory growth by a remote client that opens many QUIC streams and stalls after sending only 1 byte. Even with a small configured quic { worker_pool_size ... }, CoreDNS still spawns a goroutine per accepted stream (workers + waiters) and active workers can block indefinitely in io.ReadFull() with no per-stream read deadline, enabling unauthenticated remote DoS via memory exhaustion/OOM-kill.
Details
CoreDNS' DoQ server uses a global worker pool (streamProcessPool) to limit concurrent stream processing, but when the pool is full it still spawns a goroutine per accepted stream that waits to acquire a worker token: select { case s.streamProcessPool <- ...: go ...; default: go ... wait for token ... } (core/dnsserver/server_quic.go)
Additionally, the DoQ message framing reads are blocking io.ReadFull() calls with no per-stream read deadline: readDOQMessage() reads the 2-byte length prefix and message body via io.ReadFull() (core/dnsserver/server_quic.go)
This allows an attacker to pin all workers by sending 1 byte (so io.ReadFull() blocks waiting for the second byte of the DoQ length prefix), while also creating an unbounded backlog of goroutines waiting for a worker token.
Note: this appears to be a result of an incomplete fix/regression for CVE-2025-47950 (GHSA-cvx7-x8pj-x2gw).
PoC
- Adjust COREDNS_BIN in the PoC to point at right path (see the top-level const definitions for tunables as well)
- Run python3 ./doq-dos-repro.py
- Expected sample output: *** Start CoreDNS *** Corefile: /tmp/vh-f003-doq-mem-regression/Corefile Log: /tmp/vh-f003-doq-mem-regression/coredns.log
*** Baseline sample (idle) *** rss_kib=49380 go_goroutines=17
*** Build + run partial-stream flooder *** go: downloading golang.org/x/net v0.43.0 go: downloading golang.org/x/crypto v0.41.0 go: downloading go.uber.org/mock v0.5.2 go: downloading github.com/stretchr/testify v1.11.1 go: downloading golang.org/x/sys v0.35.0 go: downloading github.com/pmezard/go-difflib v1.0.0 go: downloading github.com/davecgh/go-spew v1.1.1 go: downloading gopkg.in/yaml.v3 v3.0.1
*** Candidate sample (during attack) *** rss_kib=137968 go_goroutines=15557
*** Flooder output *** opened conns=60 streams_per_conn=256 total_streams=15360
*** Wrote results *** /tmp/vh-f003-doq-mem-regression/results.json
*** OK *** DoQ flood caused goroutine/RSS growth despite worker_pool_size.
Impact
Unauthenticated remote DoS on an encrypted DNS transport via goroutine/RSS growth leading to OOM-kill/crash and service outage.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/coredns/coredns"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.14.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-32934"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-28T22:40:38Z",
"nvd_published_at": "2026-05-05T20:16:35Z",
"severity": "HIGH"
},
"details": "### Summary\nCoreDNS\u0027 DNS-over-QUIC (DoQ) server can be driven into large goroutine and memory growth by a remote client that opens many QUIC streams and stalls after sending only 1 byte. Even with a small configured quic { worker_pool_size ... }, CoreDNS still spawns a goroutine per accepted stream (workers + waiters) and active workers can block indefinitely in io.ReadFull() with no per-stream read deadline, enabling unauthenticated remote DoS via memory exhaustion/OOM-kill.\n\n### Details\nCoreDNS\u0027 DoQ server uses a global worker pool (streamProcessPool) to limit concurrent stream processing, but when the pool is full it still spawns a goroutine per accepted stream that waits to acquire a worker token: select { case s.streamProcessPool \u003c- ...: go ...; default: go ... wait for token ... } (core/dnsserver/server_quic.go)\n\nAdditionally, the DoQ message framing reads are blocking io.ReadFull() calls with no per-stream read deadline: readDOQMessage() reads the 2-byte length prefix and message body via io.ReadFull() (core/dnsserver/server_quic.go)\n\nThis allows an attacker to pin all workers by sending 1 byte (so io.ReadFull() blocks waiting for the second byte of the DoQ length prefix), while also creating an unbounded backlog of goroutines waiting for a worker token.\n\nNote: this appears to be a result of an incomplete fix/regression for CVE-2025-47950 (GHSA-cvx7-x8pj-x2gw).\n\n### PoC\n1. Adjust COREDNS_BIN in the PoC to point at right path (see the top-level const definitions for tunables as well)\n2. Run python3 ./doq-dos-repro.py\n3. Expected sample output:\n*** Start CoreDNS ***\nCorefile: /tmp/vh-f003-doq-mem-regression/Corefile\nLog: /tmp/vh-f003-doq-mem-regression/coredns.log\n\n*** Baseline sample (idle) ***\nrss_kib=49380 go_goroutines=17\n\n*** Build + run partial-stream flooder ***\ngo: downloading golang.org/x/net v0.43.0\ngo: downloading golang.org/x/crypto v0.41.0\ngo: downloading go.uber.org/mock v0.5.2\ngo: downloading github.com/stretchr/testify v1.11.1\ngo: downloading golang.org/x/sys v0.35.0\ngo: downloading github.com/pmezard/go-difflib v1.0.0\ngo: downloading github.com/davecgh/go-spew v1.1.1\ngo: downloading gopkg.in/yaml.v3 v3.0.1\n\n*** Candidate sample (during attack) ***\nrss_kib=137968 go_goroutines=15557\n\n*** Flooder output ***\nopened conns=60 streams_per_conn=256 total_streams=15360\n\n*** Wrote results ***\n/tmp/vh-f003-doq-mem-regression/results.json\n\n*** OK ***\nDoQ flood caused goroutine/RSS growth despite worker_pool_size.\n\n\n### Impact\nUnauthenticated remote DoS on an encrypted DNS transport via goroutine/RSS growth leading to OOM-kill/crash and service outage.",
"id": "GHSA-2wpx-qpw2-g5h5",
"modified": "2026-05-08T15:27:59Z",
"published": "2026-04-28T22:40:38Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/coredns/coredns/security/advisories/GHSA-2wpx-qpw2-g5h5"
},
{
"type": "WEB",
"url": "https://github.com/coredns/coredns/security/advisories/GHSA-cvx7-x8pj-x2gw"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32934"
},
{
"type": "PACKAGE",
"url": "https://github.com/coredns/coredns"
},
{
"type": "WEB",
"url": "https://github.com/coredns/coredns/releases/tag/v1.14.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "CoreDNS\u0027 DoQ worker pool does not bound stream backlog"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.