Sql Injection in Gin with Bearer Tokens
Sql Injection in Gin with Bearer Tokens — how this specific combination creates or exposes the vulnerability
SQL injection in a Gin application using Bearer tokens arises when an endpoint that authenticates via a token also builds SQL queries from untrusted inputs. Bearer tokens typically identify the caller (e.g., an API key or OAuth token) but do not by themselves prevent injection; if the token is used only for authentication while user-controlled parameters (path, query, or body) are concatenated into SQL strings, the authentication boundary does not protect the query construction. For example, a route like /users/:org_id that authenticates a token and then interpolates org_id into a SQL string can allow an attacker to manipulate the parameter even when a valid token is presented, leading to unauthorized data access or modification.
A concrete pattern that increases risk: retrieving a token via c.GetQuery("token") or from an Authorization header, then using that identity context to build queries without validating or parameterizing additional inputs. Because Gin does not automatically sanitize values, developers must explicitly separate identity (token) from data (user input). If token-based authorization is conflated with data handling—such as using the token to select a database schema or tenant and then embedding user values directly into SQL—this creates a path for injection. Common vulnerable patterns include string concatenation or fmt.Sprintf to build queries, misuse of ORM raw queries without binds, or failing to apply the principle of least privilege per token scope. Attackers can exploit this to bypass intended tenant isolation, extract PII, or modify data, even when Bearer token checks pass.
OpenAPI/Swagger specifications can inadvertently support this risk when parameters are described as security-related but not rigorously validated at the code level. For instance, documenting a token in the securitySchemes while still passing unchecked identifiers into SQL statements creates a mismatch between declared and actual security boundaries. Because middleBrick tests unauthenticated attack surfaces and includes checks for Authentication and BOLA/IDOR, it can surface cases where endpoints accept tokens yet remain vulnerable to injection through other inputs. This is especially important when endpoints use the same parameter for both authorization context and query construction, emphasizing the need to treat token identity and data inputs as independent security domains.
Bearer Tokens-Specific Remediation in Gin — concrete code fixes
Remediation focuses on strict separation between authentication and data handling, using parameterized queries, and validating all inputs regardless of token presence. Below are concrete, idiomatic examples for Gin that demonstrate secure patterns.
1) Use parameterized queries with database/sql (or database driver) rather than string interpolation. Even when a Bearer token identifies the request, always bind user inputs with placeholders.
// Secure: parameterized query
package main
import (
"database/sql"
"net/http"
"github.com/gin-gonic/gin"
)
func getUserHandler(db *sql.DB) gin.HandlerFunc {
return func(c *gin.Context) {
// Token used for auth/Audit, not for SQL construction
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing bearer token"})
return
}
// Validate/verify token here (omitted for brevity)
orgID := c.Param("org_id")
var result SomeStruct
// Use ? placeholders (or $1/$2 for PostgreSQL) and pass arguments separately
row := db.QueryRow("SELECT id, name FROM organizations WHERE org_id = $1 AND tenant_token = $2", orgID, token)
if err := row.Scan(&result.ID, &result.Name); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
c.JSON(http.StatusOK, result)
}
}
2) If using an ORM, ensure raw SQL paths also use arguments and avoid concatenation. For GORM, prefer Where with map or struct binds instead of raw SQL strings.
// GORM secure pattern with token-based audit context
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type OrgRecord struct {
ID string `gorm:"primaryKey"`
Name string
}
func getOrgSecure(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing bearer token"})
return
}
orgID := c.Param("org_id")
var org OrgRecord
// Parameterized where; token used only for logging/audit, not SQL
if err := db.Where("org_id = ?", orgID).First(&org).Error; err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
c.JSON(http.StatusOK, org)
}
}
3) Validate and sanitize all inputs before using them in any downstream logic, including tenant/schema selection. Reject unexpected formats early to reduce the attack surface that tokens alone cannot cover.
// Validate input format before use
import "regexp"
var orgIDRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]{1,64}$`)
func validateOrgID(c *gin.Context) bool {
orgID := c.Param("org_id")
if !orgIDRegex.MatchString(orgID) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid org_id"})
return false
}
return true
}
4) Apply principle of least privilege per token scope in your application logic and database permissions. A Bearer token should not be treated as a substitute for row-level security; enforce tenant isolation explicitly in queries.
These practices ensure that authentication via Bearer tokens does not inadvertently weaken SQL safety. By combining token validation with strict input handling and parameterized queries, you reduce the risk of injection while maintaining clear separation between identity and data.
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 |