FlawOpen

flawopen.com/SQL Injection in Go/GORM Raw SQL and SQL injection

Is GORM Raw() Safe from SQL Injection? Parameter Binding in Go

CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')Reference page
Short answer

Think of a placeholder as a sealed envelope for a value: the database driver sends the value separately from the SQL instructions. GORM Raw() can bind safely when you keep the placeholder in the query and pass the value as an argument. Formatting user input into the SQL string mixes the envelope with the instructions and can change the query.

UNSAFE
// User-controlled text becomes SQL syntax
db.Raw(fmt.Sprintf(
  "SELECT * FROM users WHERE id = %s",
  userID,
)).Scan(&user)
SAFE
// The driver binds userID as a value
db.Raw(
  "SELECT * FROM users WHERE id = ?",
  userID,
).Scan(&user)

Safe GORM Raw SQL and parameter binding

GORM and Go's database/sql bind values when placeholders stay in the SQL and arguments are passed separately, for example db.Where("name = ?", userInput) or db.Raw("SELECT ... WHERE id = ?", userID). A placeholder represents a value, not SQL syntax: table names, column names, sort directions, and operators cannot be made safe by binding them as values. Select dynamic identifiers from a fixed allowlist. Methods such as Order, Select, Table, and Raw can be injectable when user input is concatenated into their SQL fragments.

How to check your codebase

rg -n --glob '*.go' '\.(Raw|Exec|Order|Select|Table)\s*\(' . rg -n --glob '*.go' 'fmt\.(Sprintf|Sprint)' .

GORM Raw SQL and parameter binding FAQ

Are GORM's chainable query methods always safe?

No. Conditions that pass values separately, such as Where("name = ?", input), use parameter binding. Concatenating input into a condition string or passing it as raw SQL syntax can still inject a query. Some methods accept identifiers or SQL fragments that are not escaped; inspect their arguments and allowlist dynamic structure.

Can a placeholder bind a table or column name?

No. Placeholders represent data values. For a dynamic identifier or sort direction, choose from fixed application-defined options and insert only that validated constant into the SQL structure.

References

See also SQL Injection (CWE-89): How It Works and How to Prevent It in Every Language — flawopen.com Is Escaping Quotes Enough to Prevent SQL Injection? Is Using an ORM Enough to Prevent SQL Injection? Is Knex.js Safe from SQL Injection? MyBatis ${} vs #{}: Prevent SQL Injection MySQLi vs PDO: Secure Prepared Statements Is NHibernate Safe from SQL Injection?