2 min lesson
The injection family
Compare two rows from "The injection family", then say when each one fits.
Step 1 of 2
The injection familyuntrusted data crosses into a different interpreter
Injection bugs share one root cause: data the attacker controls gets concatenated into a string that some interpreter then executes - SQL, a shell, an HTTP client, a template engine. The fix is always to keep data as data. Parameterize, don't interpolate.
- Class
- SQL injection
- One-line root cause
- User input concatenated into a query string
- Paved-road fix
- Parameterized queries / prepared statements; never string-build SQL
- Class
- Command injection
- One-line root cause
- Input passed to a shell that re-parses it
- Paved-road fix
- Pass argv arrays to
exec, never a shell string; dropshell: true
- Class
- SSRF
- One-line root cause
- Server fetches a URL the attacker supplies
- Paved-road fix
- Allowlist destinations; block link-local/metadata IPs; resolve then validate
- Class
- Template injection
- One-line root cause
- User input rendered as template source, not data
- Paved-road fix
- Render with autoescaping on; never compile user strings as templates
| Class | One-line root cause | Paved-road fix |
|---|---|---|
| SQL injection | User input concatenated into a query string | Parameterized queries / prepared statements; never string-build SQL |
| Command injection | Input passed to a shell that re-parses it | Pass argv arrays to exec, never a shell string; drop shell: true |
| SSRF | Server fetches a URL the attacker supplies | Allowlist destinations; block link-local/metadata IPs; resolve then validate |
| Template injection | User input rendered as template source, not data | Render with autoescaping on; never compile user strings as templates |
Same shape every time: untrusted data treated as code in a second interpreter.
q = f"SELECT * FROM users WHERE email = '{email}'" # injectable
cur.execute("SELECT * FROM users WHERE email = %s", (email,)) # safeSSRF is the injection that hides in plain sight. "Fetch this webhook URL" or "import from this image link" lets an attacker point your server at 169.254.169.254 and read cloud metadata credentials. An allowlist of egress hosts beats any blocklist of bad IPs, because the blocklist always misses a representation (decimal IPs, DNS rebinding, IPv6-mapped).