Injection happens when untrusted input is interpreted as code or commands. It remains one of the most damaging web vulnerabilities.
When user input is concatenated directly into a SQL query, an attacker can alter the query's logic.
1// ❌ NEVER do this — string concatenation
2const q = "SELECT * FROM users WHERE email = '" + email + "'";If email is ' OR '1'='1, the query becomes:
1SELECT * FROM users WHERE email = '' OR '1'='1'...which returns every user. Worse payloads can read other tables, dump password hashes, or (with stacked queries) modify data.
1// ✅ Parameterized / prepared statement
2const user = await db.query(
3 "SELECT * FROM users WHERE email = $1",
4 [email]
5);The database treats email strictly as data, never as SQL. This is the single most important defense. ORMs (Prisma, etc.) parameterize by default — but raw queries can still be vulnerable.
When user input reaches a shell command:
1// ❌ Vulnerable
2exec("ping -c 1 " + userInput);Input like 8.8.8.8; rm -rf / runs arbitrary commands. Fix: avoid shelling out; if you must, use APIs that pass arguments as an array (no shell), and strictly validate input.
1// ✅ Safer — no shell interpretation, args array
2execFile("ping", ["-c", "1", userInput]);Watch logs for SQL syntax in parameters, sudden errors, or unusual query volumes. Database activity monitoring and WAF logs are valuable detection sources.