BT / FIELD NOTESNO. 001 / SQL INJECTION

A SMALL INPUT. A BIG PROBLEM.

LITTLE
BOBBY
TABLES.

One unusual name.
One very bad day for a database.

A visual lesson in what happens when a program mistakes someone’s words for its own instructions.

Meet the exploit ↘
SCROLL TO INVESTIGATE ↓
Cream, black and red poster: a red lightning bolt splits a database above a schoolboy. Class dismissed. Bobby Tables.
EXHIBIT A THE NAME THAT BROKE THE ROLL CALL

01 / THE ORIGIN STORY

He’s a joke.
The bug isn’t.

Bobby Tables comes from Randall Munroe’s xkcd comic “Exploits of a Mom” (#327). A school enters a child’s unusual name—and loses its student records.

The punchline is SQL injection: an application builds a database command by stitching untrusted input into SQL. Input can then change what the command means.

The real lesson? A name should never get to rewrite the instructions.

THE NAME, UNDER A MAGNIFYING GLASS

Robert');DROP TABLE Students;--

01 / THE DISGUISERobert begins as ordinary text.

02 / THE BREAKOUT'); closes the string and INSERT, then ends the statement.

03 / THE COMMANDDROP TABLE requests removal of the entire table.

04 / THE COVER-UP-- comments out the remainder of the line in this example.

This payload assumes a matching query shape, a driver that permits multiple statements, and permission to drop the table. SQL dialects differ; injection can still be dangerous without any of those exact conditions.

02 / THE EXPERIMENT

Enroll a student.
Watch the boundary.

Try a normal name. Then invite Bobby.
Switch query modes to see what changes.

SCHOOL ENROLLMENT FORM

How should the app build its query?

Illustrative browser-only simulation. No SQL is executed and no data is sent or saved. It models the shown payload, not every possible SQL input.

QUERY INSPECTORCONCATENATED
Ready. Run the simulation to see the outcome.
STUDENTS
01 Ada ENROLLED
02 Grace ENROLLED

03 / THE FIX

Let data
stay data.

Define the SQL structure first.
Pass the values separately.

With bound parameters, the database treats the whole name as a value. Quotes, semicolons, and SQL-looking words don’t become new instructions.

RUBY · PG DRIVER / POSTGRESQL

# Query and values travel separately.
conn.exec_params(
  "INSERT INTO students (name) VALUES ($1)",
  [name]
)

RUBY ON RAILS · ACTIVE RECORD

# Use the model API for this insert.
Student.create!(name: name)

# Use hash conditions for lookups.
Student.where(name: name)

An ORM helps when you use its safe APIs. Interpolating input into raw SQL is still unsafe.

04 / TAKE IT WITH YOU

Three rules.
Fewer bad days.

01

Parameterize values.

Use prepared statements or safe ORM APIs. Don’t build SQL by concatenating or interpolating user input.

02

Constrain structure.

Parameters represent values, not table names or sort directions. Map dynamic SQL structure to a fixed allowlist.

03

Limit the damage.

Give application database accounts only the permissions they need. Keep schema-changing privileges out of normal runtime access.

KEEP LEARNING

The source material.