Regex Dos in Gin with Firestore
Regex Dos in Gin with Firestore — how this specific combination creates or exposes the vulnerability
A Regular Expression Denial of Service (Regex DoS) occurs when a poorly constructed regular expression exhibits catastrophic backtracking on certain inputs, causing CPU usage to spike and response times to increase dramatically. In Gin, this often arises when developers use high‑level pattern matching on user‑controlled path segments or query parameters without validating or simplifying the regex. When such regex‑based routing or validation is combined with Firestore operations—such as using a path parameter to look up a document by ID or to build a query—each expensive match can trigger downstream Firestore calls, amplifying the impact.
Consider a Gin route that captures an identifier intended to match a Firestore document ID using a permissive regex like (.+) or a complex pattern with nested quantifiers. If an attacker sends a crafted string such as aaaa...x!@ designed to maximize backtracking, Gin may spend significant CPU cycles evaluating the route before deciding whether to proceed. If the handler then uses that captured group to query Firestore—for example, using the captured value as a document path—each pathological input can cause repeated or unnecessary Firestore interactions, increasing load on both the application and Firestore. This combination is especially risky when the regex is applied to untrusted input that influences document lookups, collection scans, or composite index usage in Firestore.
Moreover, if input validation relies on regex to enforce constraints (e.g., allowed characters for a Firestore document ID) and the regex is inefficient, an attacker can bypass intended restrictions or degrade performance without triggering immediate errors. Firestore itself does not perform regex evaluation; the cost is incurred in Gin before any Firestore call is made. However, if the regex leads to malformed or overly broad queries—such as using a captured group in a Where clause without strict validation—it can cause the backend to issue many small queries or inefficient scans, which compounds the denial-of-service effect under load.
Firestore-Specific Remediation in Gin — concrete code fixes
To mitigate Regex DoS in Gin when working with Firestore, focus on simplifying route patterns, avoiding complex or ambiguous regex for IDs, and validating input before it reaches Firestore queries. Prefer using explicit path segments with type constraints instead of greedy catch‑all patterns. For document IDs, enforce a strict character set and length using simple, non‑backtracking patterns or direct validation functions.
Below are concrete examples for Gin handlers that safely interact with Firestore.
1. Use fixed path parameters with validation
Instead of a broad regex, define a route with a named parameter and validate the format in the handler or via a middleware. This avoids expensive backtracking and makes intent explicit.
// Go + Gin example
package main
import (
"context"
"net/http"
"regexp"
"strings"
"github.com/gin-gonic/gin"
"cloud.google.com/go/firestore"
)
var docIDRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]{1,100}$`)
func getDocument(c *gin.Context) {
id := c.Param("id")
if !docIDRegex.MatchString(id) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid document ID"})
return
}
ctx := c.Request.Context()
client, err := firestore.NewClient(ctx, "your-project-id")
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "failed to create client"})
return
}
defer client.Close()
docRef := client.Collection("items").Doc(id)
doc, err := docRef.Get(ctx)
if err != nil || !doc.Exists() {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "document not found"})
return
}
c.JSON(http.StatusOK, doc.Data())
}
2. Avoid regex in Firestore queries; use strict equality or indexed fields
Do not construct query filters using captured regex groups. Instead, rely on exact matches or predefined allowlists. If you must filter by a pattern, perform validation first and then use equality or range queries that can leverage Firestore indexes efficiently.
// Safe query construction in Gin
func searchDocuments(c *gin.Context) {
category := c.Query("category")
// Validate category against an allowlist or strict pattern
if category == "" || !regexp.MustCompile(`^(electronics|books|clothing)$`).MatchString(category) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid category"})
return
}
ctx := c.Request.Context()
client, err := firestore.NewClient(ctx, "your-project-id")
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "failed to create client"})
return
}
defer client.Close()
iter := client.Collection("products").Where("category", "==", category).Documents(ctx)
defer iter.Stop()
var results []map[string]interface{}
for {
doc, err := iter.Next()
if err != nil {
break
}
results = append(results, doc.Data())
}
c.JSON(http.StatusOK, results)
}
3. Use middleware to reject problematic patterns early
Implement a Gin middleware that checks incoming paths for patterns known to cause backtracking (e.g., nested quantifiers like (a+)+) and reject them before they reach business logic.
func RejectMalformedRegexMiddleware() gin.HandlerFunc {
dangerousPattern := regexp.MustCompile(`(a+)+`)
return func(c *gin.Context) {
path := c.Request.URL.Path
if dangerousPattern.MatchString(path) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "malformed pattern rejected"})
return
}
c.Next()
}
}
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |