Fix NoSQL Injection in Gin
NoSQL injection in the Go/Gin ecosystem typically manifests when developers pipe raw request parameters directly into MongoDB filter maps (bson.M). Attackers exploit this by injecting operator objects—like {"$ne": null}—to bypass authentication or dump databases. As a researcher, your goal is to enforce strict type boundaries between the transport layer and the data layer.
The Vulnerable Pattern
func Login(c *gin.Context) { // VULNERABLE: User provides a JSON body like {"username": {"$ne": ""}, "password": {"$ne": ""}} var input map[string]interface{} c.BindJSON(&input)filter := bson.M{"user": input["username"], "pass": input["password"]} var result User err := collection.FindOne(context.TODO(), filter).Decode(&result) if err != nil { c.JSON(401, gin.H{"error": "failed"}) return } c.JSON(200, result)
}
The Secure Implementation
The exploit works because MongoDB drivers interpret nested maps as query operators. If you bind input to a generic map[string]interface{}, an attacker can pass a JSON object instead of a string. The fix is two-fold: First, use 'Strict Schema Binding' with Go structs and Gin's 'binding' tags to force the input into primitive types (strings). If the attacker sends an object, the binder will throw an error. Second, always construct your BSON filters using these validated variables rather than raw interface values from the request context.
type LoginReq struct { Username string `json:"username" binding:"required,alphanum"` Password string `json:"password" binding:"required"` }func Login(c *gin.Context) { var req LoginReq // SECURE: Strict struct binding enforces that input must be strings, not objects/operators if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, gin.H{“error”: “Invalid input”}) return }
// Use bson.D for ordered elements and explicit primitive values filter := bson.D{{Key: "user", Value: req.Username}, {Key: "pass", Value: req.Password}} var result User err := collection.FindOne(context.TODO(), filter).Decode(&result) if err != nil { c.JSON(401, gin.H{"error": "Unauthorized"}) return } c.JSON(200, gin.H{"status": "success"})
}
Your Gin API
might be exposed to NoSQL Injection
74% of Gin apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.