Dangling Dns in Gorilla Mux with Jwt Tokens
Dangling Dns in Gorilla Mux with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A dangling DNS record occurs when a hostname resolves to an infrastructure no longer in use, such as a decommissioned server or an orphaned load balancer. In a Go service using Gorilla Mux, if route host patterns are derived from or influenced by DNS values and JWT tokens are accepted without strict validation, an attacker can exploit the mismatch between DNS resolution and token expectations to reach unintended endpoints.
Gorilla Mux allows host matching via variables and matchers. If a route like /{tenant}.example.com is registered based on a DNS CNAME that later points to an unrelated service, and the application uses JWT tokens to gate access without verifying the token’s audience or issuer against the expected tenant or host, the token may be accepted even though the host no longer maps to the intended service. This creates a path where a valid JWT issued for one logical service boundary is presented to a different service boundary due to DNS misalignment.
For example, consider a multi-tenant API where each tenant has a subdomain validated by JWT audience claims. If a tenant’s DNS CNAME is updated to point to a new backend but the JWT validation logic only checks signature validity and not the aud claim against the current hostname, requests with a valid token for the old audience can still reach the new backend through the dangling DNS name. The combination of Gorilla Mux’s flexible host routing and permissive JWT acceptance means the attack surface includes not only malformed tokens but also tokens valid for a different host or tenant due to stale DNS state.
Additionally, if the application embeds host information in JWT claims (for example, a host or tenant claim) and uses that claim to select route variables in Gorilla Mux, an attacker who can influence DNS to point a dangling hostname to the service may supply a token with a manipulated claim to traverse across tenant boundaries or reach administrative routes. Because the scan testing for this issue includes unauthenticated attack surface exploration, it can detect mismatches between DNS resolution, routing patterns, and token validation rules that would otherwise be overlooked.
In practice, this risk falls under authentication and authorization weaknesses similar to those in the OWASP API Top 10, where broken object level authorization (BOLA) can occur when access controls fail to align with network-level identity boundaries. middleBrick detects these conditions by correlating OpenAPI host patterns, runtime DNS-derived endpoints, and JWT validation behavior, flagging scenarios where tokens accepted by the service do not enforce strict audience or host constraints.
Jwt Tokens-Specific Remediation in Gorilla Mux — concrete code fixes
Remediation centers on ensuring JWT validation includes host and audience checks and that Gorilla Mux routes do not rely on mutable DNS-derived values for access control. Always validate the aud (audience), iss (issuer), and any tenant or host claim against the request’s hostname and expected service identity.
Below is a concrete, working example of JWT validation integrated with Gorilla Mux that mitigates dangling DNS risks by binding token validity to the request host and enforcing strict claims.
package main
import (
"context"
"net/http"
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/gorilla/mux"
)
type Claims struct {
Tenant string `json:"tenant"`
jwt.StandardClaims
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/api/{tenant}/resource", secureHandler).Methods("GET")
http.ListenAndServe(":8080", r)
}
func secureHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
requestTenant := vars["tenant"]
requestHost := r.Host // includes port if present, e.g., api.example.com:8080
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, `{"error":"missing authorization header"}`, http.StatusUnauthorized)
return
}
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
http.Error(w, `{"error":"invalid authorization format"}`, http.StatusUnauthorized)
return
}
tokenStr := parts[1]
token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
// TODO: use a proper key management approach, e.g., JWK sets
return []byte("super-secret-key"), nil
})
if err != nil || !token.Valid {
http.Error(w, `{"error":"invalid token"}`, http.StatusUnauthorized)
return
}
claims, ok := token.Claims.(*Claims)
if !ok {
http.Error(w, `{"error":"invalid token claims"}`, http.StatusUnauthorized)
return
}
// Bind token identity to request host and route variable
if claims.Tenant != requestTenant {
http.Error(w, `{"error":"tenant mismatch in token"}`, http.StatusForbidden)
return
}
// Validate audience to prevent acceptance of tokens intended for dangling DNS names
aud := claims.StandardClaims.Audience
if aud == "" || !strings.Contains(aud, requestHost) {
http.Error(w, `{"error":"audience does not match request host"}`, http.StatusForbidden)
return
}
// Validate issuer to ensure tokens are from the expected identity provider
iss := claims.StandardClaims.Issuer
if iss == "" || iss != "https://auth.example.com" {
http.Error(w, `{"error":"issuer not allowed"}`, http.StatusForbidden)
return
}
w.Write([]byte(`{"status":"ok"}`))
}
Key points in this remediation:
- Extract the tenant from the Gorilla Mux route variable and compare it to a
tenantclaim in the JWT. - Validate the JWT
audclaim against the request host to ensure the token is intended for the current hostname, preventing acceptance of tokens valid for dangling or stale DNS names. - Validate the JWT
issclaim to tie tokens to a specific identity provider, reducing the impact of tokens issued for incorrect audiences. - Use proper key management in production instead of a hardcoded secret; the example uses a placeholder for clarity.
For automated verification, middleBrick can scan this service to confirm that JWT validation includes host and audience checks and that no route relies on unverified DNS-derived identifiers. The CLI can be used locally with middlebrick scan <url>, while the GitHub Action can enforce that scans of staging APIs fail if such misconfigurations are detected.