Glossary
What Is SQL Injection?
SQL Injection (SQLi) is a vulnerability where attacker-supplied input is concatenated into a SQL query string, letting the attacker modify the query's meaning. Despite being identified in the 1990s, SQLi remains one of the most impactful web vulnerabilities — OWASP Top-10 lists Injection (which SQLi anchors) at A03:2021.
The classic shape
SELECT * FROM users WHERE id = ' + req.params.id becomes catastrophic when req.params.id contains 1 OR 1=1 --. Modern variants include: blind boolean (response differs based on a boolean condition), blind time-based (sleep injection), error-based (extract data via error messages), union-based (combine queries), and out-of-band (exfiltrate via DNS).
How SQUR detects SQLi
The exploitation planner identifies every endpoint that accepts user input and reaches a database query. The validator constructs a confirmation payload that extracts a benign target value (@@version for MySQL/MSSQL, version() for PostgreSQL) and verifies the response. If the validator can extract the DB version through the injection point, the finding is confirmed and reported with the actual extracted string as proof.
Remediation pattern
Use parameterised queries (prepared statements) in every database access. ORMs help (Django ORM, SQLAlchemy, Active Record) but only if you don't bypass them with raw SQL concatenation. Stored procedures help only when their parameters are themselves parameterised. Input validation is a defence layer but never a substitute — allowlist values where the domain is small (e.g. enum values), and reject the rest.
Frequently asked questions
Don't ORMs make SQLi impossible?
They make the default-case safe. But every ORM has an escape hatch for raw SQL or partial-SQL concatenation — that's where the bugs end up. SQUR's benchmark targets include ORM-using apps with raw-SQL escape hatches; the validator finds them.
What's blind SQLi?
When the response doesn't show data leakage directly. The attacker tests boolean conditions (WHERE id = 1 AND SUBSTRING(version(), 1, 1) = '5') and observes whether the response changes (different content, different status code, different timing). Slow but reliable; defeats "no error messages" defences.