← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

PDO query() vs prepare()

php CWE-89 OWASP A3:2021 CVSS 9.8 PHP 5.1+ Beginner

Also Known As

PDO query method PDO execute vs query PDO direct query unsafe

TL;DR

PDO query() executes raw SQL immediately — prepare() parameterises it. query() must never include user-controlled values.

Explanation

PDO::query($sql) sends a full SQL string to the database and executes it immediately. Any variables interpolated into that string become part of the SQL syntax itself — the database cannot distinguish data from code, which enables SQL injection. PDO::prepare() separates SQL structure from data at the protocol level: the query is compiled first, then values are bound and transmitted separately. This guarantees that input is always treated as data, never executable SQL. query() is only safe for strictly static queries with zero dynamic input.

How It's Exploited

Attacker supplies email = ' OR 1=1 -- which turns the query into a tautology, returning all users. In authentication queries, this bypasses login checks entirely.

Common Misconception

Escaping input (e.g. addslashes or manual quoting) makes query() safe. It does not — escaping is encoding-dependent, easy to bypass, and fails in edge cases. Only prepared statements enforce separation between SQL and data.

Why It Matters

Using query() with even a single user-controlled value allows attackers to modify the SQL structure — bypassing authentication, dumping entire tables, or executing destructive queries. This is one of the most common causes of full database compromise.

Common Mistakes

  • Using query() with string concatenation for 'simple' lookups — still exploitable.
  • Assuming internal or trusted input cannot be malicious — second-order SQL injection is common.
  • Using query() for convenience instead of switching to prepared statements.

Avoid When

  • Never use query() with user input, even if validated or escaped.
  • Avoid query() in any context where data may originate from a database, API, or user (second-order injection risk).

When To Use

  • Use query() only for completely static SQL with no variables (e.g. SELECT VERSION(), SHOW TABLES).
  • Use prepare() for every query that includes external input, variables, or dynamic conditions.

Code Examples

✗ Vulnerable
// SQL injection — direct interpolation
$email = $_GET['email'];
$user  = $pdo->query("SELECT * FROM users WHERE email = '$email'")->fetch();

// also unsafe — concatenation
$id = $_GET['id'];
$user = $pdo->query('SELECT * FROM users WHERE id = ' . $id)->fetch();
✓ Fixed
// query() — safe only for static SQL
$version = $pdo->query('SELECT VERSION()')->fetchColumn();

// prepare() — always for dynamic input
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);
$user = $stmt->fetch();

Added 31 Mar 2026
Edited 16 Apr 2026
Views 20
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 6 Google 3 Unknown AI 2 ChatGPT 1 Meta AI 1 Ahrefs 1
crawler 13 crawler_json 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Replace query() with prepare()->execute() whenever a query contains any variable. Only use query() for fixed, hardcoded SQL.
📦 Applies To
PHP 5.1+ web cli
🔗 Prerequisites
🔍 Detection Hints
$pdo->query("...{$var}...") or $pdo->query('...' . $var . '...')
Auto-detectable: ✓ Yes semgrep phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-89

✓ schema.org compliant