Injection

OWASP Top 10

Course 1 · Chapter 3 · A03: Injection

If you've done the SQL-injection and XSS courses, this chapter is a homecoming: A03 Injection is the family those two belong to. It's the one category where you've already gone deep twice — so here we zoom out to see the whole family, the single root cause they share, and the unified defence, then point you back to the depth.

A03: Injection — Once #1, Now #3

Injection sat at #1 for years and dropped to #3 in 2021 — and that movement tells a story. It didn't get less dangerous; rather, frameworks made the safe path the default (ORMs parameterize, template engines auto-escape), so the rate of injection fell. The 2021 category also absorbed Cross-Site Scripting (XSS), which used to be its own entry — formally recognizing that XSS is just injection aimed at the browser. So A03 now spans the whole family.

The One Root Cause

Every injection is the same bug: untrusted input parsed as code
SQLi, XSS, command injection, LDAP injection, template injection, NoSQL injection — all are one mistake: untrusted data crosses a boundary where an interpreter parses it as code instead of keeping it as data. The interpreter differs (a SQL database, the browser, the OS shell, an LDAP server, a template engine), and so does the breakout syntax, but the flaw is identical. This is the unifying idea of the whole SQLi and XSS courses — "data vs code" — and A03 is simply that idea given a Top 10 slot. Learn it once and every member of the family makes sense.

The Members of the Family

Injection typeInterpreterBreakout / exampleDeep-dive
SQL injectionSQL database' OR '1'='1SQLi course
Cross-Site Scripting (XSS)the browser<script>…</script>XSS course
OS command injectionthe OS shell; rm -rf / / && curl evilthis chapter
LDAP injectionan LDAP directory*)(uid=* filter manipulationthis chapter
NoSQL injectiona document DB{"$ne": null} operator injectionSQLi Ch. 9
Template injection (SSTI)a template engine{{7*7}}49this chapter

The One You Haven't Covered: OS Command Injection

Since SQLi and XSS have their own courses, the family member worth a closer look here is command injection — when untrusted input reaches an OS shell command. It's especially dangerous because it can mean full server compromise (remote code execution), not just data access:

// VULNERABLE — user input concatenated into a shell command const cmd = "ping -c 1 " + req.query.host; // host = "8.8.8.8; rm -rf /" exec(cmd); // runs: ping -c 1 8.8.8.8; rm -rf / ← the ; chains a second command // SAFE — pass arguments as a separate array; no shell string to inject into execFile("ping", ["-c", "1", host]); // host is an argument, never parsed as shell

Notice the fix is structurally identical to parameterized SQL queries: separate the command from the data. Passing arguments as an array (rather than building one shell string) means the input can never become shell syntax — the same "keep data off the code channel" principle, in a different interpreter.

Spot-the-Pattern: SSTI

Server-Side Template Injection is a modern family member worth recognizing: if untrusted input is rendered as a template (not just into one), the template engine evaluates it. The classic probe is {{7*7}} — if the page returns 49, the input is being evaluated as template code, which often escalates to remote code execution. The cause is the same (input treated as code); the fix is to never render user input as a template — pass it as data to a fixed template instead.

The Unified Defence

Because all injection shares one root cause, the defences rhyme across the family — and they're exactly what the SQLi and XSS courses taught:

InterpreterKeep-data-as-data defence
SQLparameterized queries / prepared statements
Browser (XSS)context-aware output encoding (+ CSP)
OS shellavoid the shell; pass args as an array (execFile)
LDAP / NoSQLparameterized/safe APIs; validate types & escape filter metachars
Templatesnever render user input as a template; pass it as data
The single principle across the whole category
Keep untrusted input as data; never let it become code — by separating the command/query/markup from the data on different channels. Parameterized queries (SQL), argument arrays (shell), output encoding (HTML), safe APIs (LDAP/NoSQL), data-not-template rendering (SSTI) are all one idea in different costumes. Supporting layers help too — allowlist input validation, least privilege (a command-injection on a low-privileged account does less), and avoiding dangerous sinks (don't call the shell at all if you can use a library) — but as in SQLi/XSS, those are defence in depth; the load-bearing fix is keeping data off the code channel.

Hands-On Exercises

Exercise 1

For each, name the injection type, the interpreter, and the unified defence: (a) ' UNION SELECT … in a search box; (b) <img src=x onerror=…> in a comment; (c) ; cat /etc/passwd in a hostname field; (d) {{7*7}} returning 49. State the one root cause they all share.

📄 View solution
Exercise 2

Given exec("ping -c 1 " + req.query.host), show how an attacker achieves command execution and why it can mean full server compromise. Write the safe version and explain why it's the same principle as parameterized SQL queries.

📄 View solution
Exercise 3

Explain why A03 moved from #1 to #3 and absorbed XSS, and why that doesn't mean injection is "solved." Then state the one principle unifying SQL, XSS, command, LDAP, NoSQL, and template injection, and give the keep-data-as-data defence for three of them.

📄 View solution

Chapter 3 Quick Reference

  • A03 Injection — once #1, now #3 (frameworks made safe defaults common); 2021 absorbed XSS as injection-into-the-browser
  • One root cause: untrusted input parsed as code instead of staying data — same bug across the whole family
  • Family: SQLi (DB), XSS (browser), OS command (shell), LDAP, NoSQL (operators), template/SSTI
  • Command injection — input into a shell (; rm -rf /) → can be full RCE; fix: avoid the shell, pass args as an array (execFile)
  • SSTI — rendering input as a template ({{7*7}}→49) → often RCE; fix: pass input as data to a fixed template
  • Unified defence: keep data off the code channel — parameterized queries (SQL) · output encoding+CSP (XSS) · arg arrays (shell) · safe APIs/type-validation (LDAP/NoSQL) · data-not-template (SSTI)
  • Plus defence in depth: allowlist validation, least privilege, avoid dangerous sinks
  • Deep-dives: SQLi course, XSS course (+ SQLi Ch. 9 for NoSQL)
  • Next chapter: A04 Insecure Design — flaws no code fix solves; threat modeling & secure-by-design