GitHub Security Advisory: GHSA-h75p-j8xm-m278
Package: github.com/coredns/coredns (GO)
Severity: HIGH (CVSS 7.5)
CWE: CWE-337: Predictable Seed in Pseudo-Random Number Generator (PRNG)
Vulnerable versions: < 1.14.2
Patched in: 1.14.2

Summary: CoreDNS Loop Detection Denial of Service Vulnerability

Details:
## Executive Summary

A Denial of Service vulnerability exists in CoreDNS's loop detection plugin that allows an attacker to crash the DNS server by sending specially crafted DNS queries. The vulnerability stems from the use of a predictable pseudo-random number generator (PRNG) for generating a secret query name, combined with a fatal error handler that terminates the entire process.

---
## Technical Details

### Vulnerability Description

The CoreDNS `loop` plugin is designed to detect forwarding loops by performing a self-test during server startup. The plugin generates a random query name (`qname`) using Go's `math/rand` package and sends an HINFO query to itself. If the server receives multiple matching queries, it assumes a forwarding loop exists and terminates.

**The vulnerability arises from two design flaws:**

1. **Predictable PRNG Seed**: The random number generator is seeded with `time.Now().UnixNano()`, making the generated qname predictable if an attacker knows the approximate server start time.

2. **Fatal Error Handler**: When the plugin detects what it believes is a loop (3+ matching HINFO queries), it calls `log.Fatalf()` which invokes `os.Exit(1)`, immediately terminating the process without cleanup or recovery.

### Affected Code

**File: `plugin/loop/setup.go`**
```go
// PRNG seeded with predictable timestamp
var r = rand.New(time.Now().UnixNano())

// Qname generation using two consecutive PRNG calls
func qname(zone string) string {
    l1 := strconv.Itoa(r.Int())
    l2 := strconv.Itoa(r.Int())
    return dnsutil.Join(l1, l2, zone)
}
```

**File: `plugin/loop/loop.go`**
```go
func (l *Loop) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
    // ... validation checks ...
    
    if state.Name() == l.qname {
        l.inc()  // Increment counter
    }

    if l.seen() > 2 {
        // FATAL: Terminates entire process
        log.Fatalf("Loop (%s -> %s) detected for zone %q...", ...)
    }
    
    // ...
}
```

**File: `plugin/pkg/log/log.go`**
```go
func Fatalf(format string, v ...any) {
    logf(fatal, format, v...)
    os.Exit(1)  // Immediate process termination
}
```

### Exploitation Window

The loop plugin remains active during the following conditions:

| Condition | Window Duration | Attack Feasibility |
|-----------|-----------------|-------------------|
| Healthy startup | 2 seconds | Requires precise timing |
| Self-test failure (upstream unreachable) | 30 seconds | **HIGH** - Extended window |
| Network degradation | Variable | Depends on retry behavior |

### Attack Scenario

**Primary Attack Vector: Network Degradation**

When the upstream DNS server is unreachable (network partition, misconfiguration, outage), the loop plugin's self-test fails repeatedly. During this period:

1. The loop plugin remains active for up to 30 seconds
2. Each self-test attempt generates an HINFO query visible in CoreDNS logs
3. An attacker with log access (shared Kubernetes cluster, centralized log