Sql Injection in Gin
How SQL Injection Manifests in Gin
SQL Injection in Gin applications typically occurs when user input is directly concatenated into SQL queries without proper sanitization. This vulnerability is particularly dangerous because Gin's simplicity and flexibility can lead developers to write concise but insecure database access code.
The most common pattern in Gin applications involves using raw SQL queries with user-supplied parameters. For example:
func getUser(c *gin.Context) {
id := c.Query("id")
db, _ := sql.Open("mysql", "user:password@/dbname")
// Vulnerable: direct string concatenation
query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", id)
rows, _ := db.Query(query)
// Process results...
}This code is vulnerable because an attacker can supply input like 1 OR 1=1 to bypass authentication or extract sensitive data. The issue becomes more severe when Gin's parameter binding is used incorrectly:
func updateProfile(c *gin.Context) {
var input struct {
UserID string `json:"user_id"`
Email string `json:"email"`
}
c.BindJSON(&input)
// Still vulnerable: string interpolation
query := fmt.Sprintf("UPDATE users SET email='%s' WHERE id=%s",
input.Email, input.UserID)
db.Exec(query)
}Another Gin-specific manifestation occurs when using GORM with raw SQL. Developers might use GORM's Raw() method but still interpolate user input:
func searchProducts(c *gin.Context) {
category := c.Query("category")
// GORM doesn't protect raw SQL
db.Raw("SELECT * FROM products WHERE category = '" + category + "'").Find(&products)
}Time-based SQL injection is also possible in Gin applications, where attackers use functions like SLEEP() or BENCHMARK() to extract information through response timing:
func checkUserExists(c *gin.Context) {
username := c.Query("username")
// Vulnerable to timing attacks
query := fmt.Sprintf("SELECT * FROM users WHERE username = '%s' AND SLEEP(5)", username)
db.Query(query)
}Gin-Specific Detection
Detecting SQL Injection in Gin applications requires both static analysis and dynamic testing. Static analysis tools can identify dangerous patterns, but dynamic scanning with middleBrick provides comprehensive coverage by testing the actual running application.
middleBrick's black-box scanning approach is particularly effective for Gin APIs because it tests the unauthenticated attack surface without requiring source code access. The scanner automatically identifies endpoints that might be vulnerable to SQL injection by:
- Testing parameter manipulation across all query parameters, path parameters, and JSON bodies
- Using time-based payloads to detect blind SQL injection
- Analyzing response patterns for SQL error messages
- Checking for different database-specific syntax variations
For Gin applications, middleBrick specifically looks for patterns like:
GET /api/users?id=1' OR '1'='1
POST /api/login { "username": "admin", "password": "' OR '1'='1" }
GET /api/products?category=shoes' UNION SELECT...The scanner's LLM/AI security module also checks for prompt injection vulnerabilities that might expose database credentials if your Gin application uses AI features. This is unique to middleBrick—no other self-service scanner tests for AI-specific security issues.
Developers can integrate middleBrick into their CI/CD pipeline using the GitHub Action:
- name: Run middleBrick Security Scan
uses: middlebrick/middlebrick-action@v1
with:
target: http://localhost:8080
fail-on-severity: high
env:
MIDDLEBRICK_API_KEY: ${{ secrets.MIDDLEBRICK_API_KEY }}This setup ensures that any SQL injection vulnerabilities are caught before deployment. The CLI tool provides similar functionality for local testing:
middlebrick scan http://localhost:8080/api --output json --severity highGin-Specific Remediation
The most effective remediation for SQL Injection in Gin applications is using parameterized queries with prepared statements. This approach ensures that user input is treated as data, not executable SQL code.
Here's the secure version of the vulnerable code examples:
func getUser(c *gin.Context) {
id := c.Query("id")
db, _ := sql.Open("mysql", "user:password@/dbname")
// Secure: parameterized query
query := "SELECT * FROM users WHERE id = ?"
rows, _ := db.Query(query, id)
// Process results...
}For GORM users, the ORM provides built-in protection when used correctly:
func searchProducts(c *gin.Context) {
category := c.Query("category")
// Secure: GORM parameter binding
db.Where("category = ?", category).Find(&products)
}When using raw SQL with GORM, always use parameter binding:
func complexQuery(c *gin.Context) {
status := c.Query("status")
limit := c.Query("limit")
// Secure: parameter binding with Raw()
db.Raw("SELECT * FROM orders WHERE status = ? LIMIT ?",
status, limit).Find(&orders)
}For Gin applications using the gin.Context binding features, validate and sanitize input before database operations:
type UpdateProfileInput struct {
UserID string `json:"user_id" binding:"required,alphanum"`
Email string `json:"email" binding:"required,email"`
}
func updateProfile(c *gin.Context) {
var input UpdateProfileInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Secure: parameterized query with validation
query := "UPDATE users SET email = ? WHERE id = ?"
db.Exec(query, input.Email, input.UserID)
}Additional security measures include implementing proper error handling to avoid information disclosure:
func safeQuery(c *gin.Context) {
id := c.Query("id")
query := "SELECT * FROM users WHERE id = ?"
var user User
if err := db.QueryRow(query, id).Scan(&user.ID, &user.Name); err != nil {
if err == sql.ErrNoRows {
c.JSON(404, gin.H{"error": "User not found"})
} else {
c.JSON(500, gin.H{"error": "Internal server error"})
}
return
}
c.JSON(200, user)
}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 |