Safeguard
AppSec

MySQL Injection Cheat Sheet: How to Detect and Stop SQLi

A defender's MySQL injection cheat sheet: the query patterns attackers probe for, how login bypass and UNION-based extraction work, and how to shut them down.

Aisha Rahman
Security Analyst
6 min read

This MySQL injection cheat sheet is written for defenders: it shows the query patterns attackers probe for so you can recognize them in your logs and code, and then it shows the one fix — parameterized queries — that actually stops them. SQL injection has sat near the top of the OWASP Top 10 for two decades because the underlying mistake is easy to make and easy to miss in review.

The goal here is detection and remediation, not exploitation. Every example is the kind of thing a scanner or a code reviewer should catch, framed so you can build defenses rather than attacks.

Why SQL injection still happens

SQL injection occurs when user-controlled input is concatenated directly into a SQL statement, so the database can no longer tell the difference between the code the developer wrote and the data the attacker supplied. The classic vulnerable pattern looks like this:

// VULNERABLE - do not do this
const q = "SELECT * FROM users WHERE email = '" + email + "'";
db.query(q);

If email contains a single quote, the attacker has broken out of the string literal and can influence the query's logic. Everything on a SQL injection attack cheat sheet is a variation on that one flaw.

Login bypass patterns to recognize

The most-searched entry on any sql injection login bypass cheat sheet is the authentication bypass. Conceptually, an attacker supplies input that makes the WHERE clause always evaluate true, so the query returns a row regardless of the real password. A tautology like ' OR '1'='1 injected into an unparameterized login query turns a specific match into a match-anything condition.

For detection, the signal in your logs is input containing SQL metacharacters — stray single quotes, OR with numeric or string equality, and comment markers such as -- or # — arriving in fields that should only ever contain an email or username. A web application firewall can flag these, but the real fix is that a parameterized login query treats ' OR '1'='1 as a literal username that simply does not exist. There is no sql injection for login when the input can never be interpreted as SQL in the first place.

UNION-based extraction, conceptually

A union sql injection cheat sheet centers on the UNION SELECT operator, which lets an attacker append a second result set onto the legitimate query to pull data from other tables. The sql injection union cheat sheet workflow an attacker follows is: determine how many columns the original query returns, find which columns are rendered back to the page, then select data from another table into those columns.

You do not need working payloads to defend against this. The detection markers are what matter: requests containing UNION, SELECT, ORDER BY <n> probing for column counts, and information_schema references (the metadata database attackers query to enumerate tables). Seeing information_schema.tables or information_schema.columns in a request parameter is almost never legitimate traffic.

-- The kind of pattern a WAF or code review should flag in input:
-- ... UNION SELECT ... FROM information_schema.tables

Blind and time-based variants (using functions like SLEEP()) leave a different fingerprint — no data comes back, but response timing changes — which is why detection should watch for both anomalous content and anomalous latency.

The one fix that matters: parameterized queries

Every technique on a sql injection attack cheat sheet collapses if the query is parameterized. With bound parameters, the SQL structure is sent to the database separately from the values, so user input is always data and can never become code.

// Node.js with mysql2 - parameterized
const [rows] = await db.execute(
  "SELECT * FROM users WHERE email = ? AND status = ?",
  [email, "active"]
);
# Python with a DB-API cursor - parameterized
cursor.execute(
    "SELECT * FROM users WHERE email = %s AND status = %s",
    (email, "active"),
)

The critical rule: the ? or %s placeholders must be real bind parameters passed to the driver, not string formatting that builds the query first. f"... {email} ..." in Python or template literals in JavaScript reintroduce the flaw.

Defense in depth around the query layer

Parameterization is the fix, but a few supporting controls contain the blast radius when something slips through:

  • Least-privilege database accounts. The application's database user should not own DROP, should not read tables it never needs, and ideally cannot reach information_schema broadly. If an injection does land, limited privileges limit the damage.
  • Input validation as a secondary layer. Validate that an email looks like an email and an ID is an integer. This is not a substitute for parameterization, but it narrows the input space.
  • Stored-procedure and ORM discipline. ORMs parameterize by default, but raw-query escape hatches (queryRaw, .raw()) reopen the door. Review those specifically.
  • Error handling. Do not return raw database errors to the client; verbose errors hand attackers the schema feedback they need for blind extraction.

Catching SQLi before it ships

Manual review misses string concatenation in large codebases, so pair it with tooling. Static analysis (SAST) flags tainted input flowing into a query sink, and dynamic testing (DAST) probes running endpoints with malformed input to see whether they respond like a vulnerable query. Our overview of dynamic application security testing explains how automated scanners exercise these patterns against a live app, and the Safeguard Academy has deeper secure-coding material on input handling.

FAQ

Is it legal to use a MySQL injection cheat sheet?

Studying injection patterns to defend or to test systems you own or are authorized to test is standard security practice. Testing systems you do not have permission to test is illegal regardless of intent. Keep it to your own applications and authorized engagements.

Do parameterized queries stop every SQL injection?

They stop injection into the values of a query, which is the overwhelming majority of cases. They do not help if you dynamically build identifiers like table or column names from user input — validate those against an allowlist instead.

Does an ORM make me immune to SQL injection?

Mostly, because ORMs parameterize by default. The exception is raw-query methods, where you can still concatenate input. Audit every raw-SQL escape hatch in your codebase.

What is the fastest way to check an existing app for SQLi?

Combine a SAST scan to find concatenated queries in source with a DAST scan against the running app. Together they catch both the code smell and the exploitable behavior.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.