Skip to content
  • SQL Injection & Parameterized Queries · SQL

SQL Injection & Parameterized Queries

LearnViaNotes @learnvianotes· 3 min read

SQL injection happens when user input is pasted into SQL text, letting an attacker change the query itself. It is still one of the most common and damaging web vulnerabilities — and it is completely preventable.

The vulnerable pattern

Python — vulnerable
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
    CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password_hash TEXT, is_admin INTEGER);
    INSERT INTO users VALUES (1, 'asha', 'x1', 1), (2, 'ravi', 'x2', 0);
""")

def find_user_unsafe(name):
    query = f"SELECT id, username FROM users WHERE username = '{name}'"   # ✗ string building
    return db.execute(query).fetchall()

print(find_user_unsafe("ravi"))              # [(2, 'ravi')]
print(find_user_unsafe("x' OR '1'='1"))      # [(1, 'asha'), (2, 'ravi')]

The input x' OR '1'='1 closes the string and adds a condition that is always true, so the query becomes:

SQL
SELECT id, username FROM users WHERE username = 'x' OR '1'='1'

With a login form that is an authentication bypass; with UNION SELECT an attacker can read other tables; with stacked queries ('; DROP TABLE users; --) in engines/drivers that allow them, destroy data.

The fix: bind parameters

Python — parameterized
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
    CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT);
    INSERT INTO users VALUES (1, 'asha'), (2, 'ravi');
""")

def find_user(name):
    return db.execute("SELECT id, username FROM users WHERE username = ?", (name,)).fetchall()

print(find_user("ravi"))             # [(2, 'ravi')]
print(find_user("x' OR '1'='1"))     # []   ← treated as a plain (odd) username

With a placeholder, the SQL text and the data travel separately; the database parses the query first and the value can never become code.

Language / driverPlaceholder
Python sqlite3? or :name
Python psycopg%s or %(name)s (not Python % formatting!)
Java JDBCPreparedStatement with ?
Node pg$1, $2
PHP PDO? or :name
C# ADO.NET@name

What parameters can't do

Placeholders stand for values only — not table names, column names, ASC/DESC or keywords. For those, map the user's choice through an allow-list:

Python — allow-list
SORTABLE = {"name": "username", "newest": "id DESC"}

def order_clause(user_choice):
    return "ORDER BY " + SORTABLE.get(user_choice, "id")    # never interpolate the raw input

print(order_clause("newest"))                    # ORDER BY id DESC
print(order_clause("id; DROP TABLE users"))      # ORDER BY id

Defence in depth

  • Parameterized queries or an ORM everywhere — including admin tools and scripts.

  • Least privilege: the app's DB user can't DROP, can't read tables it doesn't need.

  • Validate input types and lengths; escape output (injection's cousin is XSS).

  • Don't show raw database errors to users; log them.

  • Watch ORM escape hatches: raw SQL helpers, .extra(), string-built WHERE fragments.

What is SQL injection and how do you prevent it?

Do stored procedures prevent SQL injection?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report