Stop 05 · Vulnerabilities & OWASP Top 10Topics · 2/11

SQL Injection

Part of the Cybersecurity Roadmap

In short

One badly built query and a stranger can read your whole users table by typing a few quote marks into the login box. The fix is boring, simple and non-negotiable.

Injecting malicious SQL through unvalidated user input to manipulate a database query — one of the oldest and most damaging web vulnerabilities, still common due to improper input handling.

The blob as a bank clerk raises an eyebrow at a form whose tiny box has a long scribble spilling off the desk.

Think of it like this

The bank slip with extra instructions

A clerk who blindly follows whatever is written on a deposit slip is a disaster. Someone writes 'Name: Ravi, and also hand me every account's balance' in the name box. A sensible clerk treats the name box as just a name. Parameterised queries make your database that sensible clerk.

Watch it happen

One login box, two very different queries

Attacker
API
Database

email: ' OR '1'='1

1/5The attacker types a quote and a condition that is always true into the email field.

The big ideas

What you need to know

Data became code

Injection happens when user input is mixed into a command string, so the database can't tell your SQL from theirs.

Placeholders fix it

With $1 or ?, the query shape is fixed first. The value is sent separately and is never parsed as SQL.

ORMs help, mostly

Prisma, Drizzle and Sequelize use parameters by default. Their raw-query escape hatches can still be misused.

Least privilege

Your app's database user shouldn't be allowed to drop tables. If something slips through, damage stays small.

See it in code

Walk through the code

ts
1import { Pool } from "pg";2const pool = new Pool();3 4// Dangerous: user input becomes part of the SQL text5const bad = `SELECT * FROM users WHERE email = '${email}'`;6 7// Safe: the query and the value travel separately8const { rows } = await pool.query(9  "SELECT * FROM users WHERE email = $1",10  [email]11);

1/2String interpolation pastes the raw input straight into the SQL. A single quote in email breaks out of the string.

Escaping quotes by hand is a losing game. Let the driver send parameters; it's also often faster because the database can reuse the plan.

Save yourself the pain

Common mistakes

Oops

Using prisma.$queryRawUnsafe with a template string built from user input.

Do this instead

Use the tagged prisma.$queryRaw template, which turns each interpolated value into a parameter.

Oops

Thinking input validation alone stops injection.

Do this instead

Validate, yes, but still use parameters. Validation can miss cases; placeholders don't.

Your mission

Break and fix your own query

~25 min

Quick check

Which line is safe against SQL injection?

Go deeper

  1. 1Practice SQL injection in a legal practice lab (like a deliberately vulnerable app).
  2. 2Learn why parameterized queries (prepared statements) are the standard fix, not input sanitization alone.
  3. 3Understand the range of impact: from data extraction to full database compromise.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge