Injection Flaws in Fiber with Firestore
Injection Flaws in Fiber with Firestore — how this combination creates or exposes the vulnerability
Injection flaws in a Fiber API that uses Google Cloud Firestore typically arise when request inputs are used to construct queries, document paths, or Firestore field filters without validation or sanitization. Because Firestore queries accept dynamic values, concatenating user-controlled data into collection names, document IDs, or query constraints can expose the application to unintended data access or behavior that is not directly a Firestore injection but is a logic flaw in how the API builds and executes operations.
In a Fiber-based service, route parameters, query strings, and JSON bodies may be bound directly into Firestore operations. For example, using c.Params to interpolate a document ID or collection segment without validation can lead to accessing or modifying data outside the intended scope. If the API dynamically builds a Firestore collection reference such as client.Collection(c.Params("collection")), an attacker could traverse to sensitive collections. Similarly, constructing field filters by string concatenation, such as firestore.Where("uid", "==", userInput), may bypass intended scoping if userInput is not treated as a value but inadvertently alters query structure.
Although Firestore does not support traditional SQL-like injection, the risk in Fiber arises from improper handling of inputs that affect which documents are read or written. An attacker might supply crafted IDs to access other users’ data (a Broken Object Level Authorization issue), or use specially formatted values to trigger unexpected behavior in the application layer. Because Firestore operations are often chained with application logic, an injection-style flaw can lead to mass data exposure or unauthorized mutations across user boundaries.
In the context of middleBrick’s 12 security checks, Injection Flaws are assessed alongside BOLA/IDOR and Input Validation. The scanner tests whether unauthenticated endpoints reflect or execute unsafe patterns by probing dynamic endpoints that incorporate user input into Firestore operations. Real-world examples include CVE-adjacent patterns where predictable document IDs or unescaped query values allow enumeration or unauthorized access across tenant boundaries.
When using the OpenAPI/Swagger spec analysis feature, middleBrick cross-references spec definitions with runtime findings to highlight endpoints where parameters are passed into Firestore operations without adequate constraints. This helps identify cases where path or query parameters are used to form collection or document references dynamically, which is a common precursor to injection-related logic flaws.
Firestore-Specific Remediation in Fiber — concrete code fixes
To remediate injection-related risks in Fiber applications using Firestore, validate and sanitize all external inputs before using them to build Firestore queries or references. Use strongly typed parameters and avoid string interpolation for collection names or document IDs. Prefer constant or enumerated values for collections and enforce strict ID formats using validation libraries.
Below are concrete code examples for secure Fiber handlers.
Secure Document Access by Known ID
Instead of using raw user input as a document ID, validate it against an allowlist or regex and use it to fetch a specific document within a predefined collection:
package main
import (
"context"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"cloud.google.com/go/firestore"
)
func getDocument(c *fiber.Ctx) error {
ctx := c.Context()
docID := c.Params("id")
// Validate document ID format
if _, err := uuid.Parse(docID); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid document ID"})
}
client, err := firestore.NewClient(ctx, <your-project-id>)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create client"})
}
defer client.Close()
docRef := client.Collection("user_profiles").Doc(docID)
snap, err := docRef.Get(ctx)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to fetch document"})
}
if !snap.Exists() {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "not found"})
}
return c.JSON(snap.Data())
}
Dynamic Collection Name with Allowlist
If your application must use dynamic collections, validate the collection name against a strict allowlist before creating a reference:
func getFromDynamicCollection(c *fiber.Ctx) error {
ctx := c.Context()
collectionName := c.Params("collection")
allowedCollections := map[string]bool{"public_posts": true, "audit_logs": true}
if !allowedCollections[collectionName] {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid collection name"})
}
client, err := firestore.NewClient(ctx, <your-project-id>)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create client"})
}
defer client.Close()
docs, err := client.Collection(collectionName).Where("published", "==", true).Documents(ctx).GetAll()
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to query collection"})
}
var results []interface{}
for _, doc := range docs {
results = append(results, doc.Data())
}
return c.JSON(results)
}
Parameterized Queries with Input Validation
When querying with user-supplied values, treat them strictly as values in filters, not as part of the query structure:
func searchUsers(c *fiber.Ctx) error {
ctx := c.Context()
email := c.Query("email")
// Basic format validation
if email == "" || !strings.Contains(email, "@") {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid email"})
}
client, err := firestore.NewClient(ctx, <your-project-id>)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create client"})
}
defer client.Close()
iter := client.Collection("users").Where("email", "==", email).Documents(ctx)
defer iter.Stop()
var matches []interface{}
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "query failed"})
}
matches = append(matches, doc.Data())
}
return c.JSON(matches)
}
By enforcing strict input validation and avoiding dynamic construction of collection and document identifiers, you reduce the risk of injection-style flaws in Fiber applications that use Firestore. These practices align with secure coding guidance and help ensure that unauthenticated attack surface testing, as performed by middleBrick, reveals fewer critical findings.