SQL injection is still the #1 exploit. Here's why.
SQL injection has been on the OWASP Top 10 for over two decades. It should be a solved problem. It isn't.
The reason is simple: it's invisible until someone exploits it. Your app works fine. Users log in, data gets saved, queries return results. There's no visible indication that anyone could run arbitrary SQL against your database — until they do.
How it happens
You write a login query that looks like this:
SELECT * FROM users WHERE email = '$email' AND password = '$password'You build the query by putting user input directly into the string. Someone types ' OR '1'='1 as their email, and the query becomes:
SELECT * FROM users WHERE email = '' OR '1'='1' AND password = '...'Since 1=1 is always true, they're in.
The fix is one line
Use parameterized queries. Instead of building the string yourself, you pass values separately:
db.query('SELECT * FROM users WHERE email = ? AND password = ?', [email, password])The database treats the input as data, not code. The attack doesn't work.
Why it's still happening
Legacy code that predates ORMs. Developers who learned from old tutorials. Quick fixes that skip the ORM. Direct database queries written under time pressure. The fix is simple but the opportunities to forget it are many.
Scan your app. If you've got raw string concatenation in query code, find it before someone else does.