Injection

Injection in Go (Gin) Guide [Apr 2026] [CVE-2026-5551]

[Updated Apr 2026] Updated CVE-2026-5551

Overview

SQL injection remains one of the most common and impactful web vulnerabilities. In Go applications using the Gin framework, an attacker can craft requests that inject malicious SQL into concatenated queries. Successful exploitation can read or alter data, bypass authentication, or corrupt data integrity. Even when using a typed language, injection can occur if dynamic SQL is built by string concatenation rather than parameter binding. Without proper safeguards, the DB layer may reveal sensitive rows or execute unintended commands; attackers may move laterally within the system or escalate privileges. In Go Gin apps, this vulnerability often shows up when handlers take user input (path, query, or body) and interpolate it directly into SQL strings, for example via string concatenation or fmt.Sprintf, and then pass that string to database/sql functions. Because the driver will treat untrusted input as part of SQL, attackers can alter the query shape. This pattern is framework-agnostic but is a common pitfall in Gin routes that pull a parameter and directly compose a query to fetch or modify data without binding. Remediation includes using parameterized queries or prepared statements with placeholders, enabling the DB driver to safely separate code from data. Bind inputs as query parameters rather than concatenating; use Query/Exec with ? or named parameters; consider an ORM that enforces bindings. Validate and constrain input with allowlists; implement least-privilege database accounts; enable proper error handling and logging; and audit dependencies and code paths that build SQL strings. Finally, add unit and integration tests that simulate injection payloads and verify safe handling.

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "database/sql"
  "log"
  "net/http"

  "github.com/gin-gonic/gin"
  _ "github.com/mattn/go-sqlite3"
)

type User struct {
  ID       int    ` + "`" + "json:\"id\"" + "`" + `
  Username string ` + "`" + "json:\"username\"" + "`" + `
}

func vulnerableQuery(db *sql.DB, username string) ([]User, error) {
  rows, err := db.Query("SELECT id, username FROM users WHERE username = '" + username + "'")
  if err != nil {
    return nil, err
  }
  defer rows.Close()
  var users []User
  for rows.Next() {
    var u User
    if err := rows.Scan(&u.ID, &u.Username); err != nil {
      return nil, err
    }
    users = append(users, u)
  }
  return users, nil
}

func secureQuery(db *sql.DB, username string) ([]User, error) {
  rows, err := db.Query("SELECT id, username FROM users WHERE username = ?", username)
  if err != nil {
    return nil, err
  }
  defer rows.Close()
  var users []User
  for rows.Next() {
    var u User
    if err := rows.Scan(&u.ID, &u.Username); err != nil {
      return nil, err
    }
    users = append(users, u)
  }
  return users, nil
}

func setupRouter(db *sql.DB) *gin.Engine {
  r := gin.Default()
  r.GET("/vuln", func(c *gin.Context) {
    q := c.Query("username")
    users, err := vulnerableQuery(db, q)
    if err != nil {
      c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
      return
    }
    c.JSON(http.StatusOK, gin.H{"users": users})
  })
  r.GET("/fix", func(c *gin.Context) {
    q := c.Query("username")
    users, err := secureQuery(db, q)
    if err != nil {
      c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
      return
    }
    c.JSON(http.StatusOK, gin.H{"users": users})
  })
  return r
}

func main() {
  db, err := sql.Open("sqlite3", ":memory:")
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  // initialize schema
  _, err = db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT)")
  if err != nil {
    log.Fatal(err)
  }

  // seed data
  _, err = db.Exec("INSERT INTO users (username) VALUES ('alice'), ('bob'), ('charlie')")
  if err != nil {
    log.Fatal(err)
  }

  r := setupRouter(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.