Back to Blog

SQL Injection in 2025: Still Dangerous, Still Common

October 09, 2024 3 min read
SQL Injection in 2025: Still Dangerous, Still Common
Last updated:

SQL injection was first documented in the late 1990s, yet it consistently appears in the OWASP Top 10 and remains one of the most impactful vulnerabilities I encounter during penetration tests. Some estimates place SQLi behind more than 30% of all web application compromises. The question is not whether SQL injection exists -- it is why it persists despite decades of awareness. Legacy codebases, ORM misuse, developer shortcuts under deadline pressure, and the growing complexity of application stacks all contribute. SQL injection hides in batch imports, reporting engines, admin panels, and third-party integrations that construct queries on the fly. Tools like sqlmap, Burp Suite, and custom scripts remain indispensable for thorough testing.

Where SQLi Still Appears

  • Dynamic ORDER BY clauses -- Cannot be parameterized in most drivers, so developers concatenate user input directly.
  • Search and filter features -- Complex forms construct WHERE clauses dynamically when the number of conditions varies.
  • Legacy stored procedures -- Procedures using internal dynamic SQL (EXEC with concatenation) remain vulnerable even with parameterized calls.
  • ORM raw queries -- Django's raw(), SQLAlchemy's text(), and ActiveRecord's find_by_sql() bypass ORM protections entirely.
  • Batch import functionality -- CSV/Excel imports generating INSERT statements dynamically are frequently overlooked.

Modern Bypass Techniques

  • WAF bypass -- URL/double encoding, inline comments (SEL/**/ECT), case manipulation, Unicode normalization, and scientific notation evade signature-based rules.
  • Second-order injection -- Payload stored via legitimate input, triggered when another query uses the stored value without sanitization. Difficult for automated tools because injection and trigger are separate requests.
  • JSON/XML parameter injection -- Nested JSON objects or XML CDATA sections can hide injection points from traditional scanners.
  • HTTP parameter pollution -- Duplicate parameters (id=1&id=2 OR 1=1) confuse back-end parsers across different frameworks.
  • NoSQL injection parallels -- MongoDB operator injection ($gt, $ne, $regex) follows the same extraction logic against unsanitized query operators.

Blind SQL Injection

  • Boolean-based -- Different application responses for true/false conditions extract data bit by bit.
  • Time-based -- SLEEP(), WAITFOR DELAY, or pg_sleep() introduce measurable delays when conditions are true.
  • Out-of-band -- DNS exfiltration via xp_dirtree (MSSQL) or LOAD_FILE() with UNC paths (MySQL) when other methods are impractical.

Testing Methodology

  1. Map injection points -- URL parameters, POST fields, HTTP headers (X-Forwarded-For), cookies, JSON/XML bodies.
  2. Confirm with timing -- A 5-second time-based delay is unmistakable confirmation.
  3. Determine database type -- @@version (MSSQL), version() (PostgreSQL/MySQL), banner FROM v$version (Oracle).
  4. Extract data -- UNION-based first (fastest), then boolean-based, then time-based. Schema first, then sensitive data.
  5. Automate with sqlmap -- Use --level=5 --risk=3 for thorough testing; always verify findings manually with Burp Suite.

Impact Demonstration

  • Data extraction -- Sample records from sensitive tables to prove severity, limited to minimum necessary.
  • Authentication bypass -- ' OR '1'='1 payloads or offline cracking of extracted admin hashes.
  • OS command execution -- xp_cmdshell (MSSQL), INTO OUTFILE/LOAD_FILE() (MySQL), COPY TO/FROM PROGRAM (PostgreSQL).
  • Database privilege escalation -- Low-privilege user to DBA via EXECUTE AS (MSSQL) or overly permissive grants.

Defense in Depth

  • Parameterized queries -- Primary defense with no exceptions for any database interaction.
  • ORM best practices -- Use query builders exclusively; parameterize even raw queries.
  • Least privilege accounts -- Only SELECT/INSERT/UPDATE/DELETE on specific tables. Never grant FILE, EXECUTE, or admin privileges.
  • WAF as supplementary defense -- Defense in depth, but never the primary mitigation. WAFs can be bypassed; parameterized queries cannot.
  • Input validation -- ORDER BY parameters should accept only allowlisted column names, never raw user input.

SQL injection is technically solved by parameterized queries. It persists due to human factors: legacy code, time pressure, and incomplete understanding of database interaction points. Our job as penetration testers is to find these gaps before attackers do.

Vid Grosek

Vid Grosek

Ethical Hacker & Penetration Tester

I help Slovenian companies discover security vulnerabilities before attackers do. Over 5 years of penetration testing experience.

All Posts

Comments

No comments yet. Be the first!

Leave a Comment

Enjoyed this article?

Subscribe to the newsletter for monthly security insights.

Subscribe