Concept · Application & cloud security
Injection and parameterized queries
Never build a query or command by pasting in user input; pass the input as a parameter instead.
Injection happens when untrusted input is mixed into something that gets interpreted, such as a SQL query, a shell command, an LDAP filter or a template, so that the input changes the instruction instead of being treated as data.
// ✗ Vulnerable: the input becomes part of the SQL
q := "SELECT * FROM users WHERE email = '" + email + "'"
// email = "' OR '1'='1" → returns every user
// email = "'; DROP TABLE users; --" → worseThe fix: keep code and data separate
Parameterized queries (prepared statements) send the SQL text and the values separately. The database parses the query before it sees the values, so a value can never become SQL:
row := db.QueryRowContext(ctx, "SELECT id, name FROM users WHERE email = $1", email)cur.execute("SELECT id, name FROM users WHERE email = %s", (email,))Escaping by hand isn't a fix. It's easy to get wrong for some encoding, quote style or context.
Where it still gets through
- Identifiers can't be parameters. Table names, column names and
ORDER BYdirection can't be bound. Check them against an allowlist:if sort not in {"created_at", "total"}: reject. - ORM escape hatches. Raw-query helpers, string-built
WHEREfragments and.extra()calls bring the risk back. - Dynamic
INlists. Use the driver's array support, such as= ANY($1)in PostgreSQL, rather than joining strings.
Same bug, other interpreters
| Interpreter | Safe pattern |
|---|---|
| Shell | Run the program directly with an argument list: exec.Command("convert", in, out), never sh -c with string building |
| HTML | Context-aware escaping in the template engine; see XSS |
| NoSQL | Typed query builders; reject objects where you expect strings ({"$ne": null}) |
| LLM prompts | No full separation exists; see prompt injection |
Defence in depth limits the damage when a bug slips through. Give the app's database user least privilege (no DROP, no access to other schemas), and let SAST tools flag string-built queries in review. The secure coding lesson covers the rest of the OWASP Top 10.