Saturday, December 13, 2025

CoreDNS Vulnerability Allows Attackers to Exhaust Server Memory Through Amplification Attack

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:

  1. max_streams: Limits concurrent QUIC streams per connection (default: 256).
  2. 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:goworkers := 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_streams receive a RESOURCE_LIMIT error.

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):textsum 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).

Recent News

Recent News