From d8b640da8dee07f2f13447f4d9e26303d2b4cfb5 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Mon, 8 Dec 2025 13:33:32 +0000 Subject: [PATCH] Add 5s timeout to DNS auth lookup to prevent resource exhaustion The DNS auth endpoint was vulnerable to resource exhaustion if an attacker controlled a domain with a slow/non-responding authoritative DNS server. Without a timeout, handler goroutines would block on DNS resolution indefinitely, allowing an attacker to pile up goroutines until OOM. Production is protected by NGINX ingress's default 60s proxy timeout, but this adds defense-in-depth with a tighter 5s bound. Also fixes the vulnerability for local development which doesn't have NGINX in front. --- internal/api/handlers/v0/auth/dns.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/api/handlers/v0/auth/dns.go b/internal/api/handlers/v0/auth/dns.go index 87a812ab..5129486d 100644 --- a/internal/api/handlers/v0/auth/dns.go +++ b/internal/api/handlers/v0/auth/dns.go @@ -6,6 +6,7 @@ import ( "net" "net/http" "strings" + "time" "github.com/danielgtaylor/huma/v2" v0 "github.com/modelcontextprotocol/registry/internal/api/handlers/v0" @@ -77,11 +78,15 @@ func RegisterDNSEndpoint(api huma.API, pathPrefix string, cfg *config.Config) { // ExchangeToken exchanges DNS signature for a Registry JWT token func (h *DNSAuthHandler) ExchangeToken(ctx context.Context, domain, timestamp, signedTimestamp string) (*auth.TokenResponse, error) { keyFetcher := func(ctx context.Context, domain string) ([]string, error) { + // Apply a timeout to DNS lookup to prevent resource exhaustion from slow/malicious DNS servers + timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + // Lookup DNS TXT records // DNS implies a hierarchy where subdomains are treated as part of the parent domain, // therefore we grant permissions for all subdomains (e.g., com.example.*) // This is in line with other DNS-based authentication methods e.g. ACME DNS-01 challenges - txtRecords, err := h.resolver.LookupTXT(ctx, domain) + txtRecords, err := h.resolver.LookupTXT(timeoutCtx, domain) if err != nil { return nil, fmt.Errorf("failed to lookup DNS TXT records: %w", err) }