Pii Leakage in Gin with Firestore
Pii Leakage in Gin with Firestore — how this specific combination creates or exposes the vulnerability
When building a REST API with the Gin framework and persisting data in Google Cloud Firestore, PII leakage commonly arises from mismatched data modeling, broad query permissions, and unchecked reflection or JSON serialization behavior. Firestore’s document-level permissions and flexible schema can inadvertently expose sensitive fields if rules and application logic do not enforce least-privilege access at both the database and API layers.
In Gin, developers often unmarshal query parameters or request JSON directly into structs using c.ShouldBindJSON. If the struct embeds or exposes fields such as Email, PhoneNumber, or government IDs without explicit omission rules, those fields may be serialized back in HTTP responses, logged, or cached. Firestore documents that contain the same fields can amplify this risk: a single document read that returns a user profile may surface sensitive PII to an endpoint that should only return a subset of data, such as display name and public avatar URL.
Another common pattern is using Firestore client libraries with overly permissive authentication, such as default service account credentials in server-side code that lack tight rules. If an endpoint queries a collection like users/{userID} and returns the full document without field-level filtering, PII such as email, address, or internal identifiers can be exposed. MiddleBrick’s unauthenticated scan can detect endpoints that return sensitive fields without requiring authentication, highlighting cases where Firestore data is directly surfaced by Gin handlers.
Reflection-based binding in Gin can also contribute to leakage. For example, binding to map[string]interface{} or using c.Request.Body without schema validation may allow clients to request fields that the developer did not intend to expose. When those keys match Firestore document fields, sensitive data can be returned inadvertently. MiddleBrick’s Property Authorization and Data Exposure checks are designed to surface such findings, including mappings to OWASP API Top 10 and compliance frameworks like GDPR and SOC2.
Additionally, Firestore’s subcollections and array-merge behaviors can create hidden pathways for PII exposure when combined with broad query patterns in Gin. A handler that aggregates data from multiple documents might concatenate user metadata, payment tokens, or internal IDs into a response that appears safe but contains sensitive elements. Continuous monitoring in the Pro plan helps detect regressions in these patterns by scanning on a configurable schedule and alerting when new PII-bearing fields appear in API outputs.
Firestore-Specific Remediation in Gin — concrete code fixes
To mitigate PII leakage in Gin applications using Firestore, enforce strict field selection, structured binding, and defensive copying. Always define explicit structs that omit sensitive fields for public endpoints, and use Firestore’s projection queries to retrieve only the necessary fields.
1. Use selective Firestore field retrieval
Instead of retrieving entire documents, specify the fields you need. This reduces the attack surface and prevents accidental exposure of PII stored in the same document.
import (
"context"
"firebase.google.com/go/v4"
"cloud.google.com/go/firestore"
"google.golang.org/api/iterator"
)
func getUserPublicProfile(client *firestore.Client, userID string) (map[string]interface{}, error) {
ctx := context.Background()
iter := client.Collection("users").Doc(userID).Select("displayName", "avatarUrl").Documents(ctx)
doc, err := iter.Next()
if err == iterator.Done {
return nil, nil
}
if err != nil {
return nil, err
}
return doc.Data(), nil
}
2. Define separate request/response structs with JSON omitempty
Create distinct structures for input binding and output serialization. Use json:"email,omitempty" to ensure sensitive fields are excluded unless explicitly required and authorized.
type UserPublicResponse struct {
DisplayName string `json:"displayName"`
AvatarURL string `json:"avatarUrl"`
}
func GetPublicProfile(c *gin.Context) {
userID := c.Param("userID")
profile, err := getUserPublicProfile(c.Request.Context(), userID)
if err != nil {
c.AbortWithStatusJSON(500, gin.H{"error": "unable to load profile"})
return
}
resp := UserPublicResponse{
DisplayName: profile["displayName"].(string),
AvatarURL: profile["avatarUrl"].(string),
}
c.JSON(200, resp)
}
3. Validate and restrict query parameters in Gin
Avoid binding raw query parameters to Firestore field names. Normalize inputs and allowlist only safe fields for projection.
var query struct {
Fields []string `json:"fields" binding:"required"`
}
if c.ShouldBindJSON(&query) != nil {
c.AbortWithStatusJSON(400, gin.H{"error": "invalid request"})
return
}
allowed := map[string]bool{"displayName": true, "avatarUrl": true}
var selected []string
for _, f := range query.Fields {
if allowed[f] {
selected = append(selected, f)
}
}
// Use selected to build a Select query as shown above
4. Enforce Firestore security rules to complement application logic
Even when Gin filters fields, secure Firestore rules to restrict read access to sensitive paths. Rules should align with the principle of least privilege, allowing reads only for permitted fields and users.
Example rule concept (not executable in Gin but critical for defense in depth):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth != null && request.auth.uid == userId
&& request.resource.data.keys().hasAll(['displayName', 'avatarUrl']);
}
}
}
5. Audit and monitor with middleware
Add Gin middleware to log response fields and detect potential PII exposure in real time. Combine this with MiddleBrick’s Data Exposure and Property Authorization checks to continuously validate that only intended fields are returned.
func AuditResponse(c *gin.Context) {
c.Next()
// Inspect response keys and compare against allowlist
// Trigger alerts or metrics when unexpected fields appear
}
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |