Injection

Injection in Go (Gin) Security Guide [May 2026] [CVE-2026-7046]

[Updated May 2026] Updated CVE-2026-7046

Overview

Injection vulnerabilities in Go (Gin) typically appear when user-supplied data is concatenated into SQL or command strings, or used to influence template rendering. In real-world Go services, endpoints frequently read query parameters, form values, or JSON fields and then construct raw queries or commands. If these inputs are not properly isolated from code, an attacker can alter query semantics, extract or modify data, bypass authentication, or cause denial of service. This guide covers the general class of injection risks in Gin without referencing CVEs. In Gin-based apps, the most common scenario is building SQL statements via string concatenation and performing db.Query or db.Exec with the resulting string. Other variants include dynamically composing IN lists, ORDER BY clauses, or OS-level commands from untrusted input. While Go's templates are designed to be safe, templates can still pose risks if untrusted content is parsed or executed, so caution applies there as well. Impact and risk come from data leakage, integrity loss, or restricted account exposure; for remote code execution to occur, the app must combine input with OS commands or template evaluation in a way that allows code execution. The result can be a compromised database, stale data, or service outages. This risks all environments where unvalidated input is accepted and used in downstream code. Remediation focuses on eliminating raw input usage in dynamic strings, adopting parameterized queries, validating and constraining inputs, and auditing for dangerous patterns in templates or command invocations. Pair Go's database/sql with prepared statements, use placeholders for user data, prefer safe ORMs or query builders, and enforce least privilege for the database user. Combine with static analysis and security testing to detect concatenated SQL, and monitor for suspicious activity.

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "database/sql"
  "log"
  "net/http"
  "github.com/gin-gonic/gin"
  _ "github.com/go-sql-driver/mysql"
)

type User struct {
  ID int `json:"id"`
  Email string `json:"email"`
}

func vulnerableQuery(c *gin.Context, db *sql.DB) {
  user := c.Query("user")
  // Vulnerable: user input concatenated into SQL string
  query := "SELECT id, email FROM users WHERE username = '" + user + "'"
  rows, err := db.Query(query)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error":"internal"})
    return
  }
  defer rows.Close()
  var users []User
  for rows.Next() {
    var u User
    if err := rows.Scan(&u.ID, &u.Email); err != nil {
      continue
    }
    users = append(users, u)
  }
  c.JSON(http.StatusOK, users)
}

func safeQuery(c *gin.Context, db *sql.DB) {
  user := c.Query("user")
  // Safe: parameterized query to prevent injection
  query := "SELECT id, email FROM users WHERE username = ?"
  rows, err := db.Query(query, user)
  if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error":"internal"})
    return
  }
  defer rows.Close()
  var users []User
  for rows.Next() {
    var u User
    if err := rows.Scan(&u.ID, &u.Email); err != nil {
      continue
    }
    users = append(users, u)
  }
  c.JSON(http.StatusOK, users)
}

func main() {
  dsn := "user:pass@tcp(localhost:3306)/dbname"
  db, err := sql.Open("mysql", dsn)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  r := gin.Default()
  r.GET("/vuln", func(c *gin.Context) { vulnerableQuery(c, db) })
  r.GET("/safe", func(c *gin.Context) { safeQuery(c, db) })
  if err := r.Run(":8080"); err != nil {
    log.Fatal(err)
  }
}

CVE References

Choose which optional cookies to allow. You can change this any time.