SQL Injection via GORM Query Builder Methods

HIGH

User-controlled input flows into GORM query builder methods (Order, Where, Group, Having) that accept raw SQL string fragments — GORM does not escape these clause arguments.

Rule Information

Language
Go
Category
Security
Author
Shivasurya
Shivasurya
Last Updated
2026-04-13
Tags
gosecuritysql-injectiongormquery-builderorder-by-injectionCWE-89OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset golang/GO-GORM-SQLI-002 --project .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Cross-file analysis: 3 files

About This Rule

Understanding the vulnerability and how it is detected

GORM's query builder methods — Order(), Group(), Having(), Where() with string arguments, Select(), Distinct(), Pluck() — accept raw SQL string fragments for clause construction. Unlike GORM's struct-based conditions which are automatically parameterized, these string-accepting methods pass the argument directly into the SQL clause without escaping.

**ORDER BY injection** is the most common pattern: sorting direction and column selection are frequently exposed as API parameters (`?sort=name&direction=asc`). ORDER BY cannot be parameterized in SQL (placeholders only work for values, not identifiers like column names). This creates a structural injection risk unless column names are validated against an allowlist before being passed to GORM.

**GORM's own documentation** explicitly warns about this pattern in the Security section: "User's inputs should be validated before being used as a query parameter. When using Order(), Group(), or Having() with user input, use allowlist validation."

**Attack example**: `db.Order(r.FormValue("sort"))` with sort value `(SELECT SLEEP(3))` causes a time delay, confirming blind injection. With `name; DROP TABLE users;--` on MySQL, stacked queries may execute.

**Real-world pattern — Fleet**: Fleet (open-source device management platform, 25k+ GitHub stars) has historically exposed API sort parameters directly to GORM's Order() method without allowlist validation. ORDER BY injection is a structural risk in any data-table API that exposes sort column parameters to users.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Blind Time-Based SQL Injection

Injecting `(SELECT SLEEP(5))` (MySQL) or `(SELECT pg_sleep(5))` (PostgreSQL) into an Order() call causes a response delay, confirming injection. Attackers can then exfiltrate data character-by-character via timing channels without any visible output change.

2

ORDER BY Column Enumeration

Injecting column names not in the SELECT list (e.g., `password ASC`) causes a database error revealing schema information. This enables attackers to discover table columns for targeted UNION attacks.

3

Stacked Query Execution

On MySQL and SQL Server where stacked queries are supported, injected semicolons can terminate the ORDER BY clause and execute additional SQL statements, enabling data manipulation or schema changes.

4

Authenticated API Exploitation

These vulnerabilities often appear in administrative API endpoints that expose sort/filter parameters for data tables. Authenticated attackers (including low-privilege users) can exploit these endpoints to access data they should not see.

How to Fix

Recommended remediation steps

  • 1Validate all user-supplied ORDER BY column names against an explicit string allowlist.
  • 2Never pass raw user input to Order(), Group(), Having(), or Select() as a string.
  • 3Use GORM struct conditions for WHERE clauses: db.Where(&Model{Field: value}).
  • 4Use ? placeholder for string-based Where with values: db.Where("col = ?", value).
  • 5For complex filtering APIs, define a mapping from API parameter names to SQL column names.
  • 6Enable GORM logging in staging to inspect all generated SQL.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

Tracks taint from HTTP framework sources to GORM query builder methods that accept raw SQL strings: Order(), Group(), Having(), Where() with string first argument, Select(), Joins(), with global inter-procedural scope.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A03:2021 — Injection
CWE Top 25 (2024)
CWE-89 — SQL Injection (ranked #6)
PCI DSS v4.0
Requirement 6.2.4 — Protect against injection attacks

References

External resources and documentation

Similar Rules

Explore related security rules for Go

Frequently Asked Questions

Common questions about SQL Injection via GORM Query Builder Methods

GORM's query builder methods — Order(), Group(), Having(), Where() with string arguments, Select(), Distinct(), Pluck() — accept raw SQL string fragments for clause construction. Unlike GORM's struct-based conditions which are automatically parameterized, these string-accepting methods pass the argument directly into the SQL clause without escaping. **ORDER BY injection** is the most common pattern: sorting direction and column selection are frequently exposed as API parameters (`?sort=name&direction=asc`). ORDER BY cannot be parameterized in SQL (placeholders only work for values, not identifiers like column names). This creates a structural injection risk unless column names are validated against an allowlist before being passed to GORM. **GORM's own documentation** explicitly warns about this pattern in the Security section: "User's inputs should be validated before being used as a query parameter. When using Order(), Group(), or Having() with user input, use allowlist validation." **Attack example**: `db.Order(r.FormValue("sort"))` with sort value `(SELECT SLEEP(3))` causes a time delay, confirming blind injection. With `name; DROP TABLE users;--` on MySQL, stacked queries may execute. **Real-world pattern — Fleet**: Fleet (open-source device management platform, 25k+ GitHub stars) has historically exposed API sort parameters directly to GORM's Order() method without allowlist validation. ORDER BY injection is a structural risk in any data-table API that exposes sort column parameters to users.
Use Code Pathfinder to scan your codebase: pathfinder scan --ruleset golang/GO-GORM-SQLI-002 --project .
This vulnerability is rated as HIGH severity.
Yes! Code Pathfinder allows you to customize rules. Modify detection patterns, adjust severity levels, add custom sanitizers, and configure the rule to fit your organization's security policies.

New feature

Get these findings posted directly on your GitHub pull requests

The SQL Injection via GORM Query Builder Methods rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works