Token Leakage in Gin with Firestore
Token Leakage in Gin with Firestore — how this specific combination creates or exposes the vulnerability
Token leakage in a Gin application that uses Firestore typically occurs when authentication tokens or session identifiers are inadvertently exposed through API responses, logs, or error messages. This risk is heightened because Firestore operations in Gin often involve marshaling and unmarshaling sensitive data structures, and mishandling request context can propagate tokens to unintended outputs.
For example, when a Gin handler decodes a Firestore document into a Go struct, a developer might inadvertently include a token field (e.g., AuthToken or AccessToken) in the struct. If that struct is serialized into JSON for an HTTP response, the token can be exposed to clients or logged by middleware. A common pattern that creates risk:
type UserProfile struct {
UID string `json:"uid"`
Email string `json:"email"`
AuthToken string `json:"auth_token" // unsafe: token in response
}
func GetProfile(c *gin.Context) {
uid := c.Param("uid")
ctx := context.Background()
client, err := firestore.NewClient(ctx, "my-project")
if err != nil { /* handle */ }
defer client.Close()
doc, err := client.Collection("users").Doc(uid).Get(ctx)
if err != nil { c.JSON(500, gin.H{"error": err.Error()}); return }
var profile UserProfile
if err := doc.DataTo(&profile); err != nil {
c.JSON(500, gin.H{"error": err.Error()}); return
}
c.JSON(200, profile) // risk: AuthToken included in response
}
In this pattern, if the Firestore document contains a field that maps to AuthToken, the token is returned in clear text to the caller. Additionally, tokens can leak through Gin’s error handling when error messages include raw Firestore document contents or when structured logging captures request and response bodies containing tokens. The LLM/AI Security checks in middleBrick specifically flag such leakage by scanning for patterns where sensitive fields are included in JSON outputs, helping identify these exposures during automated scans.
Another vector involves URL parameters and query strings. If a token is passed as a query parameter to a Gin endpoint that interacts with Firestore (e.g., /api/data?token=xxx), and that endpoint logs the full request or echoes parameters, the token can appear in logs or be exposed through insecure referer headers. Firestore security rules do not protect against application-level logging, so sensitive data must be stripped or omitted before being handled by Gin handlers.
Tokens may also leak through SSRF-related interactions. An attacker could manipulate Firestore document fields to contain URLs that cause the Gin service to make outbound requests, embedding tokens in outbound headers or query strings. middleBrick’s SSRF and Data Exposure checks help detect whether Firestore data could be used to exfiltrate tokens via these indirect channels.
Finally, insecure deserialization of Firestore data can lead to token leakage. If a Gin app deserializes Firestore map-based documents into loosely typed map[string]interface{} and later includes that map in responses, tokens stored as fields in Firestore documents may be unintentionally surfaced. Careful schema definition and field exclusion are required to prevent this.
Firestore-Specific Remediation in Gin — concrete code fixes
To remediate token leakage when using Firestore with Gin, explicitly control which fields are serialized in HTTP responses and ensure tokens are never part of structures sent to the client. Use separate structs for database models and API responses, and omit sensitive fields from JSON tags or use - to exclude them.
Safe approach: define a Firestore document model that includes the token for internal operations, and a separate response model that excludes it.
type UserProfileDB struct {
UID string `firestore:"uid"`
Email string `firestore:"email"`
AuthToken string `firestore:"auth_token"`
}
type UserProfileResponse struct {
UID string `json:"uid"`
Email string `json:"email"`
// AuthToken intentionally omitted
}
func GetProfileSafe(c *gin.Context) {
uid := c.Param("uid")
ctx := context.Background()
client, err := firestore.NewClient(ctx, "my-project")
if err != nil { http.Error(c.Writer, "internal error", 500); return }
defer client.Close()
doc, err := client.Collection("users").Doc(uid).Get(ctx)
if err != nil {
c.JSON(500, gin.H{"error": "unable to fetch profile"})
return
}
var dbProfile UserProfileDB
if err := doc.DataTo(&dbProfile); err != nil {
c.JSON(500, gin.H{"error": "data parse error"}); return
}
response := UserProfileResponse{
UID: dbProfile.UID,
Email: dbProfile.Email,
}
c.JSON(200, response)
}
When updating Firestore documents, avoid passing token fields from request input. Use explicit whitelists for updatable fields to prevent attackers from injecting or modifying token fields.
type UpdateProfileRequest struct {
Email string `json:"email" validate:"required,email"`
// Do not include token fields here
}
func UpdateProfile(c *gin.Context) {
uid := c.Param("uid")
var req UpdateProfileRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "invalid request"}); return
}
ctx := context.Background()
client, err := firestore.NewClient(ctx, "my-project")
if err != nil { http.Error(c.Writer, "internal error", 500); return }
defer client.Close()
updates := make(map[string]interface{})
if req.Email != "" {
updates["email"] = req.Email
}
// Never include token from request; use server-side values if needed
_, err = client.Collection("users").Doc(uid).Update(ctx, updates)
if err != nil {
c.JSON(500, gin.H{"error": "update failed"}); return
}
c.Status(204)
}
For error handling, avoid echoing raw Firestore errors that might contain document data or tokens. Instead, use generic messages and log detailed errors server-side without exposing them to the client.
func GetProfileWithErrorHandling(c *gin.Context) {
uid := c.Param("uid")
ctx := context.Background()
client, err := firestore.NewClient(ctx, "my-project")
if err != nil { c.Status(500); return }
defer client.Close()
doc, err := client.Collection("users").Doc(uid).Get(ctx)
if err != nil {
// Log detailed error internally; return generic response
c.Status(404)
return
}
var profile UserProfileResponse
if err := doc.DataTo(&profile); err != nil {
c.Status(500)
return
}
c.JSON(200, profile)
}
Validate and sanitize all inputs that influence Firestore queries to avoid injection or leakage via query parameters. Do not rely on Firestore security rules to prevent token exposure at the application layer.
middleBrick’s API scans complement these fixes by detecting whether tokens appear in JSON responses or are exposed through error messages. Its LLM/AI Security checks specifically identify patterns where authentication tokens could be leaked in model outputs, helping catch issues before deployment.