Visual walkthrough — Security — OWASP Top 10, input validation, authentication vs authorization
We assume you have never seen SQL, a parse tree, or an injection. We earn every word.
Step 1 — What a query even is
The database can't act on English, so we write it in a fixed language called SQL (see SQL Databases). Our example instruction looks like this:
WHAT we did: named the pieces of a query. WHY: every attack below is about smuggling something past that quote fence, so we must see the fence first. PICTURE: below, the command words are one colour, the data (Alice) is another, and the quotes are the fence between them.

Step 2 — The machine reads a query as a tree, not a line
WHAT we did: introduced , the shape of a parsed query. WHY: an injection attack is precisely "the attacker managed to add a new branch to this tree." If we can freeze the tree's shape, we win. PICTURE: the same Alice query, now drawn as a tree — Alice sits alone at a leaf, harmless, while WHERE and = form the logic above it.

Step 3 — Building the query by gluing strings (the fragile way)
Real apps don't hard-code 'Alice'; the name comes from a user typing into a form (see HTTP and Web Fundamentals). The tempting shortcut is to glue the user's text into the middle of the query.
The catch: becomes part of the same sentence the parser reads. The user's data is now sitting inside the grammar, not safely fenced off. When the parser reads the glued result, it can't tell which letters came from you and which came from the user — it's all one string now.
WHAT we did: wrote the vulnerable construction as a formula. WHY: to expose the flaw — is fed to the parser, so can influence the tree. PICTURE: two ribbons ( and ) being stitched into one continuous line before the parser sees it.

Step 4 — The attack: reshaping the tree with one quote
Now the attacker types this as their "name":
Glue it in and the full sentence becomes:
Watch the quotes carefully — this is the whole trick:
The result: the tree grew a new branch (an OR node) that you never wrote. That is injection — added a node to .
WHAT we did: showed one character rewriting the parse tree. WHY: this is the mechanism behind the parent's warning "untrusted input is interpreted as code." PICTURE: the clean tree from Step 2 with a red, attacker-grown OR branch bolted on top.

Step 5 — The fix: send code and data on separate channels
Instead of gluing into the sentence, we send the template with a placeholder — a ? — and hand the value over on a separate wire.
Because the shape of the tree is frozen the instant is parsed, literally cannot add a node — even if is x' OR '1'='1, those characters are stored as the name value, quotes and all. The database will faithfully search for a user literally named x' OR '1'='1 and find nobody.
WHAT we did: split the one channel into two — template first, value second. WHY: the parent's central claim, "attack surface for parse-tree injection ", follows directly: no data-to-parser path means no injectable node. PICTURE: two clearly separate pipes — a "code pipe" carrying to the parser, and a "data pipe" carrying straight to a leaf slot, never touching the grammar.

Step 6 — Edge & degenerate cases (the parent's contract: cover them all)
A proof isn't done until the weird inputs behave. Let's stress-test the parameterized design:
| Input | Concatenation result | Parameterized result |
|---|---|---|
Alice (normal) |
finds Alice ✔ | finds Alice ✔ |
x' OR '1'='1 (classic) |
dumps all rows ✘ | searches for that exact literal name → 0 rows ✔ |
'' (empty string) |
matches empty names ✔ | matches empty names ✔ (a leaf can hold empty text) |
Robert'); DROP TABLE users;-- (the "Bobby Tables" attack) |
deletes the table ✘ | searches for that exact literal name → 0 rows ✔ |
a value with a quote inside a name, e.g. O'Brien |
breaks the query / injects ✘ | stored correctly as the name O'Brien ✔ |
WHAT we did: ran every category of input — normal, malicious, empty, destructive, and honest-but-quoted — through both designs. WHY: the reader must never meet a scenario we didn't show. PICTURE: a two-column verdict board, green ticks all down the parameterized side.

Recall Quick self-check
If '; DROP TABLE users;--, why does the parameterized version not drop the table? ::: Because is never parsed as SQL — the tree was already built from the template's ?, so u can only be stored as a literal value in a leaf. It becomes a (nonexistent) username to search for, not a command.
In , which symbol is the danger and why? ::: — because concatenation feeds it into the parser, letting it add nodes to the parse tree .
The one-picture summary

The whole walkthrough in one frame: top path (concatenation) fuses and into one string, the parser reads it all, and the attacker's ' grafts a rogue OR branch — a poisoned tree. Bottom path (parameterization) parses alone into a fixed, clean tree, then drops into a leaf slot that can never become a branch. Same input, two fates. This is why the parent note could write "attack surface " — not as a hope, but as a structural guarantee. (For the deeper "trust the value, distrust the parser" mindset, see Threat Modeling and Principle of Least Privilege.)
Recall Feynman: retell the whole walkthrough to a 12-year-old
Imagine you send a note to a robot cook: "Make a sandwich with [filling]." If you let a stranger write the filling and you just paste their words into your note, a nasty stranger writes "cheese. Also, burn down the kitchen." — and the robot, reading one long note, obeys the whole thing. That's the glued (concatenation) way, and one sneaky punctuation mark lets them add a new order. The safe way: you hand the robot a note with a blank — "Make a sandwich with ▢" — and you place the stranger's word into the blank on a separate card. The robot already decided the note only has one instruction (make a sandwich); the card can only fill the blank, never add a new order. So even if the stranger's card says "cheese. Also burn the kitchen," the robot just looks for a filling literally called "cheese. Also burn the kitchen," shrugs, and finds none. The blank-and-card trick is a parameterized query, and it's why separating the recipe from the ingredient makes the whole class of "sneaky-note" attacks impossible.