Cache Poisoning in Gin with Bearer Tokens
Cache Poisoning in Gin with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Cache poisoning occurs when an attacker causes a cache (e.g., CDN, reverse proxy, or in-memory cache) to store responses that are specific to one user or context and then served to other users. In the Gin framework, this risk can emerge when responses that include sensitive authorization information, such as Bearer Tokens, are cached based on request path or query parameters without considering headers like Authorization.
When a Gin endpoint uses path-based routing (e.g., /api/users/:id/profile) and relies on query parameters or static paths for caching, a request that includes an Authorization header with a Bearer Token may be cached. If the cache key does not exclude the Authorization header, a cached response containing a valid Bearer Token could be replayed to other users who do not have permission to view that data. This can lead to unauthorized access to protected resources and token exposure.
For example, consider a Gin route that proxies or caches upstream responses without normalizing the request headers. A request like GET /api/users/123/profile?details=full with a header Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... might be cached. If another user requests GET /api/users/123/profile?details=summary and the cache key ignores the Authorization header and query parameters that affect sensitivity, the cached response with the Bearer Token could be returned inappropriately.
In the context of OpenAPI/Swagger spec analysis, if the spec does not explicitly mark security requirements per operation or if runtime checks do not correlate Authorization headers with cache behavior, the scanner can identify mismatches between documented authentication and actual caching practices. This is especially important when specs include securitySchemes of type http with bearer format but do not enforce header exclusion from caches.
Because middleBrick scans unauthenticated attack surfaces and runs 12 security checks in parallel, it can detect scenarios where responses that should not be cached due to Bearer Token presence appear in cache-sensitive endpoints. Findings include identifying missing Vary headers, improper cache key construction, and lack of authorization-aware caching logic in Gin handlers.
Bearer Tokens-Specific Remediation in Gin — concrete code fixes
To remediate cache poisoning risks involving Bearer Tokens in Gin, ensure that responses containing sensitive authorization data are not cached, or that cache keys incorporate headers and context that prevent cross-user exposure.
1. Exclude Authorization header from cache keys and do not cache responses with Bearer Tokens.
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/api/users/:id/profile", func(c *gin.Context) {
auth := c.GetHeader("Authorization")
if auth == "" || !isBearerToken(auth) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing or invalid bearer token"})
c.Abort()
return
}
// Do not cache responses that contain bearer tokens
c.Header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
c.Header("Vary", "Authorization")
c.JSON(http.StatusOK, gin.H{"message": "profile data"})
})
r.Run()
}
func isBearerToken(auth string) bool {
// Basic check: "Bearer <token>"
return len(auth) > 7 && auth[:7] == "Bearer "
}
2. Use Vary headers and avoid caching when tokens are present.
func profileHandler(c *gin.Context) {
token := c.GetHeader("Authorization")
if token != "" {
// Ensure cached responses are not shared across users
c.Header("Vary", "Authorization")
// Indicate no caching to intermediaries
c.Header("Cache-Control", "private, no-cache")
}
c.JSON(http.StatusOK, gin.H{"user": "safe_data"})
}
3. For scenarios where upstream caching is required, normalize requests by stripping or hashing the Authorization header for cache key generation on the server side, and never include raw Bearer Tokens in stored responses.
func getCacheKey(c *gin.Context) string {
path := c.Request.URL.Path
query := c.Request.URL.RawQuery
// Exclude Authorization from cache key; do not store responses with tokens
return path + "?" + query
}
These examples demonstrate how to align Gin handlers with secure caching practices when Bearer Tokens are involved, reducing the risk of token leakage via cache poisoning.