HIGH dangling dnsgorilla muxjwt tokens

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 tenant claim in the JWT.
  • Validate the JWT aud claim 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 iss claim 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.

Frequently Asked Questions

How does validating the JWT audience against the request host prevent dangling DNS exploits?
Validating the audience ensures the token was issued for the specific hostname handling the request. If DNS points a dangling or stale hostname to your service, a token with an audience that does not match the current host will be rejected, preventing unauthorized access across tenant or service boundaries.
Can Gorilla Mux host variables alone secure multi-tenant APIs when JWTs are used?
No. Host variables in Gorilla Mux should not be trusted for access control without JWT validation that includes explicit checks for tenant, audience, and issuer. An attacker could manipulate host-based routing if tokens are accepted without verifying claims against the request target.