Ssrf Server Side in Gin with Firestore
Ssrf Server Side in Gin with Firestore — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a Gin application that interacts with Google Firestore can arise when user-supplied input is used to form HTTP requests or to construct Firestore resource references without strict validation. In this stack, an attacker may supply a malicious URL or document path that causes the server to make unintended internal requests or to access Firestore resources it should not reach. For example, if an endpoint accepts a Firestore document path from a query parameter and passes it directly to the Firestore client, an attacker can reference internal metadata services or other projects by supplying paths such as http://metadata or manipulated Firestore paths that bypass intended access controls.
Gin does not automatically validate or sanitize inputs used to build Firestore client calls, so developers must enforce strict allowlists for document IDs and collection names. A vulnerable pattern is concatenating user input into a Firestore path and then using the Firestore Go SDK to retrieve data, which may cause the server to follow injected redirections or SSRF-inducing HTTP calls when the Firestore client or underlying HTTP transport is misconfigured. In a black-box scan, middleBrick tests such endpoints by submitting crafted document paths and metadata-service targets to detect whether the server performs unauthorized internal requests or exposes sensitive data through misrouted Firestore lookups.
Because Firestore rules are enforced client-side in some implementations, server-side code must also enforce its own authorization checks. If the Gin handler trusts user input to determine which Firestore document to read or write, and does not validate that the authenticated subject has permission on that specific document, the SSRF vector can combine with broken access control to yield unauthorized data exposure. middleBrick’s checks include submitting path traversal and internal network indicators to see whether the server performs outbound requests to sensitive endpoints, and whether Firestore operations reflect user-controlled input without proper validation.
Firestore-Specific Remediation in Gin — concrete code fixes
Remediation centers on strict input validation, avoiding direct concatenation of user input into Firestore document paths, and using Firestore’s built-in APIs safely. Always treat document IDs and collection names as untrusted, and validate them against an allowlist or a strict regex before using them with the Firestore client.
Example: Safe Firestore document read in Gin
package main
import (
"context"
"fmt"
"net/http"
"regexp"
"github.com/gin-gonic/gin"
"cloud.google.com/go/firestore"
"google.golang.org/api/iterator"
)
var validID = regexp.MustCompile(`^[a-zA-Z0-9_-]{1,100}$`)
func getDocument(c *gin.Context) {
// Assume Firestore client is initialized elsewhere and passed in
client, _ := firestore.NewClient(context.Background(), "my-project-id")
defer client.Close()
collection := c.Param("collection")
docID := c.Param("docID")
// Validate collection and document ID
if !validID.MatchString(collection) || !validID.MatchString(docID) {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid collection or document ID"})
return
}
ctx := context.Background()
iter := client.Collection(collection).Doc(docID).Documents(ctx)
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to read document"})
return
}
if doc.Ref == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "document not found"})
return
}
data := doc.Data()
c.JSON(http.StatusOK, gin.H{"data": data})
break
}
}
Key points in the example:
- Use a strict regex to validate collection and document inputs instead of relying on Firestore security rules alone.
- Use the Firestore Go SDK’s
CollectionandDocmethods with validated identifiers rather than building paths from raw strings. - Do not follow user-supplied URLs or redirects; if you must fetch external resources, use a tightly scoped HTTP client with a deny-list of private IP ranges and metadata service targets.
Example: Parameterized Firestore query with allowlisted fields
func queryWithAllowlist(c *gin.Context) {
client, _ := firestore.NewClient(context.Background(), "my-project-id")
defer client.Close()
// Accept only specific, known fields from query params
field := c.Query("field")
value := c.Query("value")
allowedFields := map[string]bool{"status": true, "region": true, "tags": true}
if !allowedFields[field] {
c.JSON(http.StatusBadRequest, gin.H{"error": "field not allowed"})
return
}
iter := client.Collection("items").Where(field, "==", value).Documents(context.Background())
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "query failed"})
return
}
c.JSON(http.StatusOK, gin.H{"id": doc.Ref.ID, "data": doc.Data()})
}
}
Additional measures include configuring the HTTP transport used by the Firestore client to block connections to private IP ranges and metadata endpoints, and enforcing least-privilege IAM roles for the service account used by the Gin application. middleBrick’s scans validate that such controls are observable in runtime behavior by checking for SSRF indicators and improper access patterns across the 12 security checks.