SQL injection is the canonical example of mixing data and code. A query string like "SELECT * FROM users WHERE id = " + userId looks fine when userId is 42. It looks catastrophic when userId is 1 OR 1=1 --. The database doesn't know which characters were yours and which arrived from a stranger over the network — it parses the whole thing as one statement.
The fix has been the same for two decades: use parameterized queries (also called prepared statements or bound parameters). Every mainstream database driver supports them. The driver sends the query template and the values along separate channels, so the values can never become part of the SQL grammar no matter how exotic the punctuation.
What makes SQL injection sneaky in 2026 is the long tail of places it survives. Production code rarely concatenates strings into raw SELECTs anymore, but it still happens in dynamic ORDER BY clauses (where parameters can't help you and you need a strict allowlist), in admin tools written in haste, in reporting pipelines that pass user-typed filter expressions through, and in ORMs whose escape hatches drop you back to raw SQL. A code-review reflex worth building: any time you see a string operator (+, f"...", format, concat) building SQL, flag it until proven safe.
Review heuristic
Every SQL string built from concatenation is guilty until proven innocent. If the value originated in a request — directly or indirectly through a stored field a user once supplied — it has to flow through a parameterized binding. ORDER BY and dynamic table names need an allowlist, never a passthrough.
External reference
CWE-89: Improper Neutralization of Special Elements used in an SQL Command — the canonical industry classification for this bug class. Useful when filing tickets, writing security policies, or arguing with a static analyzer.