Overview
Injection vulnerabilities in Go (Gin) apps enable attackers to manipulate data, bypass authentication, or execute unintended commands when untrusted input is embedded into queries or system calls. In production, compromised endpoints can exfiltrate customer data, corrupt records, or escalate privileges across the application if user-supplied input controls critical logic. These risks are common even when using Gin as the HTTP router, because the vulnerability typically resides in how the application builds database queries, file paths, or shell commands from request data. Note: no CVE IDs are provided in this guidance; this is a general, implementation-focused remediation guide based on typical injection scenarios in Go (Gin).
Code Fix Example
Go (Gin) API Security Remediation
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"os/exec"
_ "github.com/go-sql-driver/mysql"
"github.com/gin-gonic/gin"
)
var db *sql.DB
func init() {
var err error
db, err = sql.Open("mysql", "user:pass@tcp(localhost:3306)/mydb")
if err != nil { log.Fatal(err) }
}
func vulnerableHandler(c *gin.Context) {
id := c.Query("id")
// vulnerable: string concatenation in SQL
query := fmt.Sprintf("SELECT id, email FROM users WHERE id = %s", id)
rows, err := db.Query(query)
if err != nil { c.String(http.StatusInternalServerError, "db error"); return }
_ = rows
rows.Close()
c.Status(http.StatusOK)
}
func fixedHandler(c *gin.Context) {
id := c.Query("id")
// fixed: parameterized query
row := db.QueryRow("SELECT id, email FROM users WHERE id = ?", id)
var uid int
var email string
err := row.Scan(&uid, &email)
if err != nil {
if err == sql.ErrNoRows {
c.Status(http.StatusNotFound)
return
}
c.String(http.StatusInternalServerError, "db error"); return
}
c.String(http.StatusOK, fmt.Sprintf("user: %d %s", uid, email))
}
func vulnerableCommandHandler(c *gin.Context) {
term := c.Query("term")
cmd := exec.Command("/bin/sh", "-c", "grep "+term+" file.txt")
out, _ := cmd.Output()
c.String(http.StatusOK, string(out))
}
func fixedCommandHandler(c *gin.Context) {
term := c.Query("term")
cmd := exec.Command("grep", term, "file.txt")
out, _ := cmd.Output()
c.String(http.StatusOK, string(out))
}
func main() {
r := gin.Default()
r.GET("/vulnerable", vulnerableHandler)
r.GET("/fixed", fixedHandler)
r.GET("/vuln-cmd", vulnerableCommandHandler)
r.GET("/fixed-cmd", fixedCommandHandler)
r.Run()
}