GHSA-qhmp-q7xh-99rh
HIGHGHSA-qhmp-q7xh-99rh is a high-severity (CVSS 7.5) CWE-303 vulnerability in github.com/coredns/coredns. O3 Security confirms whether GHSA-qhmp-q7xh-99rh is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
CoreDNS has TSIG authentication bypass on DoT, DoH, DoH3, DoQ, and gRPC
Real-World Exposure
github.com/coredns/corednsReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
CoreDNS' tsig plugin can be bypassed on non-plain-DNS transports because it trusts the transport writer's TsigStatus() instead of performing verification itself. In the attached PoC, plain DNS/TCP correctly rejects an invalid TSIG (NOTAUTH), while the same invalid-TSIG request is accepted over DoT (tls://) and DoH (https://), allowing a client without the shared secret to satisfy require all. The same bug class affects DoH3, DoQ, and gRPC.
Details
The tsig plugin decides whether an incoming TSIG was valid by consulting w.TsigStatus(): tsigStatus := w.TsigStatus(); if tsigStatus != nil { ... NOTAUTH ... } (plugin/tsig/tsig.go)
Two affected transports are shown directly in the PoC:
- DoH: DoHWriter.TsigStatus() always returns nil (core/dnsserver/https.go), and the HTTP server passes unpacked DNS messages directly into the plugin chain.
- DoT: the TLS server builds a dns.Server without setting TsigSecret (core/dnsserver/server_tls.go), unlike plain DNS/TCP/UDP which sets TsigSecret: s.tsigSecret (core/dnsserver/server.go).
The same transport-family bug pattern also appears on other transports:
- DoH3 reuses the DoH writer path (core/dnsserver/server_https3.go -> core/dnsserver/https.go), so it inherits the same TsigStatus() == nil behavior.
- DoQ uses DoQWriter.TsigStatus() error { return nil } (core/dnsserver/quic.go).
- gRPC uses gRPCresponse.TsigStatus() error { return nil } (core/dnsserver/server_grpc.go).
The attached PoC was kept deliberately small (baseline TCP+DoT+DoH only) for convenience.
PoC
- Adjust COREDNS_BIN in the PoC to point at right path (see the top-level const definitions for tunables as well)
- Run python3 ./tsig-repro.py
- Expected output: *** Start CoreDNS *** Corefile: /tmp/vh-f001-tsig-doh-dot-bypass/Corefile Log: /tmp/vh-f001-tsig-doh-dot-bypass/coredns.log
*** Baseline (plain TCP) *** no_tsig rcode=5 (expected REFUSED=5) invalid_tsig rcode=9 (expected NOTAUTH=9)
*** Candidate (DoT) *** no_tsig rcode=5 (expected REFUSED=5) invalid_tsig rcode=0 ancount=1 (expected NOERROR=0 and ancount>0)
*** Candidate (DoH) *** no_tsig http=200 rcode=5 (expected REFUSED=5) invalid_tsig http=200 rcode=0 ancount=1 (expected NOERROR=0 and ancount>0)
*** OK *** TSIG bypass reproduced: plain TCP rejects invalid TSIG, while DoT and DoH accept it. Results: /tmp/vh-f001-tsig-doh-dot-bypass/results.json
Impact
Unauthenticated remote clients can bypass TSIG-based authentication/authorization on first-class encrypted transports, enabling access to whatever the deployment intended to restrict behind tsig { require all } (e.g., zone data/privileged queries, etc.).
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/coredns/coredns | all versions | 1.14.3 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/coredns/coredns. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update github.com/coredns/coredns to 1.14.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-qhmp-q7xh-99rh is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-qhmp-q7xh-99rh is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-qhmp-q7xh-99rh. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-qhmp-q7xh-99rh in your dependencies?
O3 detects GHSA-qhmp-q7xh-99rh across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.