Overview
CVE-2026-35579 describes a CoreDNS vulnerability where TSIG-based authentication could be bypassed: the server would treat requests as authenticated if the TSIG key name existed in the configuration, or in the DoH/DoH3 variants would always return a nil TSIG status without inspecting the MAC. This allowed an unauthenticated attacker to bypass TSIG-protected operations such as zone transfers or dynamic DNS updates. The issue was fixed in CoreDNS 1.14.3. As a workaround, operators were advised to disable or isolate TSIG-reliant transports (gRPC, QUIC, DoH, DoH3) or restrict access to those ports. In the Go ecosystem, including Go services built with Gin, a similar broken-authentication pattern can occur when a service uses a presence-based check (e.g., a configured key name exists) and then fails to verify the cryptographic signature or token, effectively granting access without proper verification. This guide ties the real-world CVE to Go (Gin) patterns and shows concrete remediation steps and code fixes.
Affected Versions
CoreDNS < 1.14.3 (1.14.0-1.14.2 affected); DoH/DoH3 variants also addressed in the CVE, with fix in 1.14.3
Code Fix Example
Go (Gin) API Security Remediation
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"os"
"github.com/gin-gonic/gin"
)
// Simple in-memory key store for demonstration. In production, use a secure vault.
var keyStore = map[string]string{
"v1-service": "sharedsecret1",
}
func main() {
mode := os.Getenv("MODE") // MODE=VULN to run vulnerable version, else FIXED
r := gin.Default()
if mode == "VULN" {
r.Use(vulnerableAuthMiddleware)
} else {
r.Use(fixedAuthMiddleware)
}
r.GET("/secure", func(c *gin.Context) {
if v, ok := c.Get("authenticated"); ok && v.(bool) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
return
}
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
})
r.Run()
}
// Vulnerable pattern: authenticates based solely on the presence of a configured key,
// without validating the accompanying MAC/signature.
func vulnerableAuthMiddleware(c *gin.Context) {
keyName := c.GetHeader("X-Auth-Key")
mac := c.GetHeader("X-Auth-MAC")
if keyName == "" || mac == "" {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
if _, ok := keyStore[keyName]; ok {
// BUG: Do not verify MAC; treat as authenticated if keyName exists
c.Set("authenticated", true)
c.Next()
return
}
c.AbortWithStatus(http.StatusUnauthorized)
}
// Fixed pattern: verify the MAC against the expected HMAC with per-key secret.
func fixedAuthMiddleware(c *gin.Context) {
keyName := c.GetHeader("X-Auth-Key")
macHeader := c.GetHeader("X-Auth-MAC")
if keyName == "" || macHeader == "" {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
secret, ok := keyStore[keyName]
if !ok {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
expected := computeHMAC(c.Request.Method+":"+c.Request.URL.Path, secret)
if !hmac.Equal([]byte(macHeader), []byte(expected)) {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
c.Set("authenticated", true)
c.Next()
}
func computeHMAC(message, secret string) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil))
}