Vulnerabilities/SQL Injection
SQL Injection
SQL injection happens when an application builds a query by gluing user input into the SQL text, so the database parses part of that input as commands. The fix is the same in every language: send the query with placeholders and pass the values separately. Pick your language below for the exact API calls, vulnerable and fixed code, and the CI rules that catch it.
Plain English Explainer (ELI5)
You hand a librarian a slip that reads 'Fetch the record for: ___' and write in the blank: 'John. Also unlock the archive and bring every file.' A librarian who reads the whole slip as one set of instructions does both. Gluing user input into a SQL string builds exactly that slip. A parameterized query is a printed form with a sealed box marked 'name': whatever is written inside is only ever looked up as a name, however it is worded.
Core Concepts & Subsystem Terms
- SQL injection (CWE-89)
- Untrusted input is concatenated or formatted into SQL text, so quotes, keywords and operators in the input change the structure of the query instead of being treated as one value.
- Prepared statement and bind parameters
- The query is sent with placeholders (
?,$1,:name) and parsed before any value arrives; the values travel separately and are always treated as data. This is the primary defense in every driver and ORM. - Blind SQL injection
- When the page shows no query results or errors, an attacker infers data one bit at a time from differences in the response (boolean-based) or its timing (time-based). No visible output does not mean no vulnerability.
- Second-order SQL injection
- A value is stored safely, later read back from your own database and concatenated into a different query. Every query must be parameterized, including queries whose inputs come from your own tables.
- Identifiers and allowlists
- Placeholders carry values only, not table names, column names or sort directions. Those must be picked from a fixed allowlist in code, never copied from the request.
Step-by-Step Attack Flow
Input reaches a query
A form field, URL parameter, header or API field is passed to code that builds a SQL statement.
The input is glued into SQL text
Concatenation, interpolation or formatting inserts the value directly. The benign test value ' OR '1'='1 turns WHERE name = '...' into a condition that is always true.
The database parses it as syntax
The database receives one string, cannot tell which part came from the user, and runs the altered statement with the application's privileges.
Data is read, changed or deleted
Depending on the query and the account, the attacker bypasses a login, dumps tables with UNION queries or extracts data blind. The 2023 MOVEit Transfer breach (CVE-2023-34362) began with this class of flaw.
SQL injection guides by language
Engineering & System Hardening Checklist
- Parameterize every query that contains a value, including raw-SQL escape hatches in ORMs, with no exceptions for internal or numeric inputs.
- Pick table names, column names and sort directions from hard-coded allowlists.
- Run a SAST rule for string-built SQL in CI (Bandit, gosec, Semgrep, CodeQL, Find Security Bugs, Brakeman or Psalm) and fail the build on new findings.
- Connect with a least-privilege database role: no DDL, no superuser, only the tables the service needs.
- Treat escaping functions and WAF rules as extra layers only; they miss unquoted contexts and encoding tricks.
- Return generic errors to clients and log database errors server-side, so the query structure is never revealed.
Sources
- CWE-89: SQL Injection
- OWASP SQL Injection Prevention Cheat Sheet
- CISA — CL0P ransomware campaign exploits MOVEit SQL injection