New: Try Voli The Bear, Fast package manager (and not only) for Windows
Updated Jul 10, 2026 Edit on GitHub

The One Bug Underneath Both: Mixing Data with Code

Security guides usually hand you SQL injection and XSS as two separate chores: memorize this fix for the database, memorize that fix for the web page, move on. That's why they never stick - they look unrelated, so they feel like two more spells to keep straight.

They're not unrelated. They are the same bug. Once you see the shared cause, you'll be able to predict both fixes instead of recalling them, and you'll start spotting the same shape in places this guide never even mentions.

The one idea: data should never be able to become code

Every program constantly juggles two different kinds of strings:

  • Code - instructions the machine executes. SQL statements. HTML and JavaScript a browser runs.
  • Data - values the program just handles. A username someone typed. A search term. A comment.

When you write a program, you write the code. Your users supply the data. That line - your instructions vs. their values - is supposed to be a wall.

An injection bug is a hole in that wall. It happens when a value the user supplied gets fed to some interpreter - a database, a browser - in a way that lets the value escape its role as data and get read as code instead. The user stops being someone who fills in a blank and becomes someone who can rewrite your program's instructions.

  THE WALL THAT SHOULD HOLD                THE HOLE (injection)

  ┌─────────────┐                          ┌─────────────┐
  │  your code  │  ← you write this        │  your code  │
  ├─────────────┤                          ├─────────────┤
  │ user input  │  ← stays "just a value"  │ user input  │ ─┐ input crosses the
  └─────────────┘                          └─────────────┘  │ line and is read
        the interpreter sees a clear              the interpreter can't tell  │ as CODE
        boundary: code here, data there          where code ends and the     │
                                                 user's value begins  ◄──────┘

📝 Terminology - "interpreter." Anything that takes a string and acts on its meaning: a SQL database reading a query, a web browser reading HTML, a shell running a command. Injection is always "untrusted input reaching an interpreter as code." Different interpreter, different name - same bug.

Why this keeps happening: the convenient, dangerous shortcut

Both holes are born the same way - by building a piece of code by gluing strings together, with user input glued right in the middle:

   "fixed instructions"  +  user_input  +  "more instructions"
   └──── your code ────┘    └─ their ─┘    └─── your code ───┘
                            └ value, but the interpreter only
                              sees one long string ──────────┘

When you concatenate like this, the boundary between your instructions and their value exists only in your head. By the time the interpreter receives the string, that boundary is gone - it's just one run of characters. If the user's value contains characters that mean something to the interpreter (a quote that ends a SQL string, a < that starts an HTML tag), those characters do their job, and the value reshapes the code around it.

That's the whole disease. SQL injection is this shortcut feeding a database. XSS is this shortcut feeding a browser.

The two costumes

The same bug, told twice:

SQL injection Cross-Site Scripting (XSS)
The interpreter Your database A visitor's web browser
Code it confuses input for SQL commands HTML / JavaScript
What goes wrong Input changes what the query does Input becomes script the page runs
Who gets hurt Your data (read, changed, deleted) Your users (their session, their browser)
The shape of the fix Send code and data on separate channels Encode input so it can't be read as markup

Two interpreters, two costumes - but look at the bottom row. Each fix is the same instinct applied to a different interpreter: stop letting the user's value be read as code. For the database, you do that by handing it the query and the values separately, so it never even tries to parse the value as SQL. For the browser, you do it by encoding the value so the characters that mean "this is markup" arrive as harmless text instead.

💡 Key point - the one sentence to carry into both phases. Keep data as data. You are never trying to guess and block "bad input." You're making it structurally impossible for input to be treated as code in the first place. Blocklists ("strip out the word DROP", "remove <script>") fail because attackers have endless ways to write the same thing; keeping data on its own channel can't be tricked, because the interpreter is never invited to parse the value as code at all.

⚠️ Gotcha - "I'll just validate the input and I'm safe." Input validation (rejecting an email that has no @, capping a length) is good hygiene and worth doing. But it is not the fix for injection, and leaning on it as the fix is how people get burned. Validation asks "does this look reasonable?" - a question with no reliable answer for free-text fields like names, comments, or search terms, where O'Brien and <3 are perfectly legitimate. The real fixes in Phases 2 and 3 don't depend on predicting bad input; they keep the data/code boundary intact no matter what the input contains.

Why this saves you later

Hold this one model and the rest of the guide reads like consequences, not commandments: Phase 2's "parameterize your queries" and Phase 3's "encode on output" are the same instinct, aimed at two different interpreters. And the next time you wire any input into any interpreter - a shell command, an LDAP filter, a file path - you'll feel the same alarm: keep data as data.

Recap

  1. Programs juggle code (instructions a machine runs) and data (values it just handles). The line between them is a wall.
  2. Injection is a hole in that wall - user input reaching an interpreter in a way that lets it be read as code instead of data.
  3. The usual cause is building code by gluing strings together with user input in the middle, which erases the boundary before the interpreter ever sees it.
  4. SQL injection and XSS are the same bug aimed at two interpreters: the database and the browser.
  5. The cure for both is one sentence: keep data as data - make it structurally impossible for input to become code, rather than trying to guess and filter "bad" input.

Now let's take the first interpreter - the database - and watch the wall come down, then build it back up properly.


← Guide overview · Phase 2: SQL Injection →

Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.

Check your understanding 3 questions

1. What is the one bug underneath both SQL injection and XSS?

2. What is the usual cause of both holes?

3. Why is input validation not the real fix for injection?