Xss Cross Site Scripting in Gorilla Mux with Jwt Tokens
Xss Cross Site Scripting in Gorilla Mux with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Cross-site scripting (XSS) in a Gorilla Mux router context can be amplified when JWT tokens are handled inconsistently between authenticated and unauthenticated routes. XSS occurs when an attacker injects executable script into a page viewed by other users; the risk increases if your application reflects untrusted data into HTML, JavaScript, or URL contexts without proper escaping. With Gorilla Mux, you typically define routes for public endpoints (e.g., status or documentation) and protected endpoints that require a valid JWT token in the Authorization header. If the public routes reflect query parameters, path variables, or headers without sanitization, an attacker can craft a URL containing a script payload and a valid JWT (or a predictable token) to test whether the token’s presence changes behavior in an unsafe way.
Consider a scenario where a handler reads a JWT from the Authorization header and embeds the token’s claims (such as a username or a display name) into an HTML response without escaping. Because Gorilla Mux supports variable injection via route expressions (e.g., /user/{id}), an attacker might supply a malicious value as a path or query parameter that ends up reflected alongside the token-derived data. If Content-Security-Policy is absent or misconfigured, and if the application does not enforce strict input validation and output encoding, the browser may execute the injected script in the context of the victim’s session, effectively combining JWT-based session handling with reflected XSS.
Moreover, developers sometimes expose token introspection or error messages that include the token or its parts in responses. In Gorilla Mux, middleware that extracts and validates JWTs might inadvertently pass raw token strings into templates or JSON responses when errors occur. This can expose sensitive information and create an XSS vector if the response is rendered in a browser context. The interplay of routing patterns, middleware logic, and insufficient output sanitization is what makes the combination of Gorilla Mux and JWT tokens a relevant scenario for XSS risk assessment.
Jwt Tokens-Specific Remediation in Gorilla Mux — concrete code fixes
Remediation focuses on strict input validation, safe output encoding, and secure handling of JWTs in Gorilla Mux handlers and middleware. Always treat data from path parameters, query strings, and headers as untrusted. Use context-aware escaping when inserting data into HTML, JavaScript, or URL attributes. For JWTs, avoid reflecting raw tokens or sensitive claims in responses; instead, use them strictly for authentication and authorization decisions.
Example: Safe handler with Gorilla Mux and JWT validation
package main
import (
"encoding/json"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secure-secret-key")
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, `{"error": "authorization header required"}`, 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.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, http.ErrAbortHandler
}
return jwtSecret, nil
})
if err != nil || !token.Valid {
http.Error(w, `{"error": "invalid token"}`, http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "claims", token.Claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func profileHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userID := vars["user_id"]
// Validate and sanitize userID if it originates from user input
if userID == "" {
http.Error(w, `{"error": "user_id is required"}`, http.StatusBadRequest)
return
}
claims, ok := r.Context().Value("claims").(jwt.MapClaims)
if !ok {
http.Error(w, `{"error": "claims unavailable"}`, http.StatusInternalServerError)
return
}
// Safe: constructing JSON response with proper escaping via encoding/json
resp := map[string]interface{}{
"user_id": userID,
"name": claims["name"],
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/profile/{user_id}", profileHandler).Methods("GET")
r.Use(authMiddleware)
http.ListenAndServe(":8080", r)
}
Output encoding and templating safety
If you render HTML templates, use template actions that auto-escape. For example:
import (
"html/template"
"net/http"
)
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.New("page").Parse(`
<div>Welcome, {{ .User }}</div>
`))
data := struct{ User template.HTML }{User: template.HTML("Alice")}
tmpl.Execute(w, data)
}
Always set Content-Type and consider a strong Content-Security-Policy as an additional defense-in-depth measure, but remember that CSP is not a substitute for proper input validation and output encoding.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |