A critical Denial-of-Service (DoS) vulnerability (CVE-2025-XXXX) has been patched in CoreDNS’s DNS-over-QUIC (DoQ) server implementation.
The flaw allows remote attackers to crash instances by exploiting uncontrolled goroutine creation in QUIC stream handling, leading to memory exhaustion.
This issue is particularly severe in containerized deployments where resource constraints amplify the impact.
Vulnerability Analysis: Goroutine Proliferation in QUIC Stream Handling
The vulnerability resides in server_quic.go, where CoreDNS created a new goroutine for every incoming QUIC stream without enforcing concurrency limits.
QUIC’s multiplexed stream design allows a single connection to handle thousands of simultaneous streams, but CoreDNS’s 1:1 stream-to-goroutine model enabled attackers to trigger:
go// Pre-patch code snippet (simplified)
func handleStream(s quic.Stream) {
go processStream(s) // Uncontrolled goroutine creation
}
Attack Mechanics
- Low-Bandwidth Amplification: An attacker opens millions of streams (≈1 KB/stream) via a single QUIC connection.
- Memory Consumption: Each goroutine allocates ~2–4 KB stack + DNS processing buffers. 10,000 streams ≈ 40–100 MB RAM.
- OOM Kill: Containerized environments (Kubernetes, Docker) enforce memory limits, making OOM-induced crashes likely.
Impact Profile
- CVSSv3.1: 8.6 (High) – AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
- Affected: CoreDNS 1.13.0–1.15.2 with
quic://enabled in the Corefile.
Mitigation Strategies: Bounded Concurrency and Resource Pooling
The patch (CoreDNS ≥1.15.3) introduces two concurrency controls:
max_streams: Limits concurrent QUIC streams per connection (default: 256).worker_pool_size: Global worker pool for stream processing (default: 1024).
Updated Corefile Configuration
textquic {
max_streams 256 # Streams/connection
worker_pool_size 1024 # Global worker quota
}
Architecture Changes
- Goroutines are now recycled via a buffered channel pool:go
workers := make(chan struct{}, workerPoolSize) func handleStream(s quic.Stream) { workers <- struct{}{} // Blocks if pool full defer func() { <-workers }() processStream(s) // Reuses goroutines } - QUIC connections exceeding
max_streamsreceive aRESOURCE_LIMITerror.
Workarounds and Detection
For unpatched deployments:
1. Disable QUIC
text# corefile
# Remove or comment quic:// lines
tls://. :5353 {
...
}
2. Kubernetes Resource Hardening
text# deployment.yaml
resources:
limits:
memory: "512Mi"
requests:
memory: "256Mi"
3. Anomaly Detection
- Monitor for >100 QUIC streams/connection (e.g., Prometheus):text
sum by (instance) (rate(coredns_quic_streams_total{status="opened"}[5m])) > 100
Operational Considerations
- Default Settings: CoreDNS’s post-patch defaults (256 streams/connection, 1024 workers) align with RFC 9250’s recommendations for DoQ.
- Client Compatibility: Most DoQ clients (e.g., Android 14+, quic-go) use ≤100 streams/connection.
- Attack Surface Reduction: Disable QUIC unless required for mobile/low-latency use cases.
This vulnerability highlights the risks of protocol-translation layers in DNS infrastructure. Administrators should prioritize patching and review all QUIC-enabled services for similar stream-exhaustion flaws (e.g., HTTP/3, SMB over QUIC).





