Jomel.Tr

Web Vulnerabilities — Go

Web Vulnerabilities — Go

Direct concatenation of user input into a SQL query.

! vulnerable.go
func GetUser(db *sql.DB, id string) (*User, error) {
    // id может быть: 1 OR 1=1 --
    query := "SELECT * FROM users WHERE id = " + id
    row := db.QueryRow(query)
    var u User
    err := row.Scan(&u.ID, &u.Name, &u.Email)
    return &u, err
}
secure.go
func GetUser(db *sql.DB, id string) (*User, error) {
    // Параметризованный запрос — id всегда данные, не код
    query := "SELECT * FROM users WHERE id = $1"
    row := db.QueryRow(query, id)
    var u User
    err := row.Scan(&u.ID, &u.Name, &u.Email)
    return &u, err
}

How to fix

Never concatenate SQL strings with user input. Use only parameterized queries (placeholders $1, ?), where the driver passes data separately from the query body — input cannot physically become part of the code. Validate table/column identifiers that can’t be parameterized against an allowlist. Grant DB privileges following the principle of least privilege.

Tools and practices

  • database/sql + placeholders — Standard library: db.Query("... WHERE id = $1", id). The basic approach, sufficient for most cases.
  • sqlc — Generates type-safe Go code from plain SQL at build time. Queries are checked by the compiler, injections are excluded by design.
  • ent (entgo.io) — An ORM from Meta with code generation and a type-safe query builder. Graph-oriented schema, no raw strings.
  • GORM — A popular full-featured ORM. Parameterizes automatically; avoid Raw/Exec with concatenation.
  • sqlx / squirrel — sqlx is a thin layer over database/sql; squirrel is a safe query builder that assembles parameterized queries.
  • pgx — A high-performance PostgreSQL driver with native support for prepared statements and protocol-level binding.