Join our Newsletter — 33% off our NHI Course
Home› Guides› SQL Injection Prevention Guide: Parameterised Queries and Blind…
Guide Application Security

SQL Injection Prevention Guide: Parameterised Queries and Blind SQLi

← All guides
By Lalit Choda, NHI Mgmt Group Updated 18 October 2026 16 min read
On this page

SQL injection (SQLi) has been understood and preventable for about two decades, yet it still lets attackers read, change or destroy entire databases through a single unparameterised query. In March 2024 CISA and the FBI issued a Secure by Design Alert after a managed file transfer campaign exploited SQL injection to reach thousands of organisations, and OWASP still counts more than 14,000 SQL injection CVEs in A05:2025 Injection. This guide goes deeper than the summary in the Web Application Attacks Guide: it covers the SQLi variants and what each means for detection, parameterisation in the places it is hardest (identifiers, dynamic SQL, stored procedures, ORMs such as Hibernate), blind, second-order and out-of-band injection, database privilege, detection and testing. It is for developers, application security engineers and database administrators, and it is written from the defender's side, with no injection strings or attack procedures.

Key takeaways

  • Parameterise everything that is data. Bind variables keep values out of the SQL text; CISA and the FBI call input sanitisation "brittle" and say it "frequently can be bypassed".
  • Identifiers need allowlists, not escaping. Table names, column names and sort order cannot be bound, so map user choices to fixed values; this is where many parameterised applications still fail.
  • Stored procedures and ORMs are not automatically safe. Dynamic SQL inside a procedure and string-built HQL or raw ORM queries are injectable; OWASP and CWE-564 say so explicitly.
  • Blind and second-order SQLi defeat error hiding. Suppressing database errors does not fix injection; data from your own tables is untrusted when it is concatenated into a later query.
  • Least privilege decides the blast radius. One database account per application, no owner or DBA rights, and no outbound network access from the database turn a missed injection into a contained incident.

How SQL injection works and its variants

CWE-89 describes the weakness: "The product constructs all or part of an SQL command using externally-influenced input" without neutralising elements that change its meaning. The database then executes whatever valid SQL results; Microsoft's SQL Server documentation notes that the engine "executes all syntactically valid queries that it receives". OWASP's Web Security Testing Guide (WSTG-INPV-05) groups SQL injection attacks into three classes by how data comes back, and the variants below matter mainly because each leaves different evidence.

VariantClassHow it works, conceptuallyWhat defenders see
Union-based SQL injectionIn-bandAttacker-controlled query results are appended to the application's own result setUnusual result sizes, queries touching system catalogue tables
Error-based SQL injectionIn-bandDatabase error messages returned to the client leak structure and dataBursts of syntax and conversion errors from the application account
Blind SQL injection (boolean)InferentialData is inferred one condition at a time from differences in page contentHigh volumes of near-identical requests with small parameter changes
Time-based SQL injectionInferentialDeliberate database delays answer true or false questions when nothing else differsResponse time outliers clustered on one route and client
Out-of-band SQL injectionOut-of-bandDatabase features send results over another channel, usually DNS or HTTPOutbound DNS or network connections from database servers
Stacked SQL injectionAnyWhere the driver and database accept several statements in one call, a second statement is addedWrites, schema changes or new logins from a read path
Second-order SQL injectionAnyInput is stored safely, then later read back and concatenated into another queryErrors or anomalies in batch jobs and admin functions, not the input form
Stored procedure injectionAnyA procedure builds dynamic SQL from its parametersCalls to EXEC, sp_executesql or EXECUTE IMMEDIATE with unusual arguments
ORM injectionAnyString-built HQL, JPQL or raw ORM queries, or field names taken from inputORM query exceptions in application logs

Two labels describe exposure rather than technique. Pre-auth or unauthenticated SQL injection is reachable without logging in, which is why it drives mass exploitation: CISA advisory AA23-158A describes CL0P exploiting a "previously unknown SQL injection vulnerability (CVE-2023-34362)" in the MOVEit Transfer web application from 27 May 2023. JSON-embedded SQL injection arrives inside JSON request bodies, as values or as keys, which API code often maps straight onto column names and which perimeter filters may not parse the same way the application does.

Parameterisation done properly

The Secure Coding Guide covers the basic prepared statement pattern. OWASP's Query Parameterization Cheat Sheet states "SQL Injection is best prevented through the use of parameterized queries" and lists the bind APIs for each platform: JDBC PreparedStatement, .NET SqlCommand and OleDbCommand parameters, PHP PDO, Ruby ActiveRecord placeholders, Perl DBI, ColdFusion cfqueryparam and Rust SQLx. Query parameterisation means the SQL text is fixed and values travel separately as bind variables, so the database never parses them as SQL; parameterised SQL also lets the database reuse the query plan. The hard cases are the parts of a query that cannot be bound.

ConstructWhy it goes wrongSafe pattern
Values in WHERE, INSERT, UPDATEString concatenation or formattingBind variables, typed where the API allows (Microsoft: the Parameters collection treats input "as a literal value")
Table and column namesIdentifiers cannot be bound; OWASP calls user-chosen names "a symptom of poor design"Map each user option to a fixed identifier in code; reject anything not in the map
Sort direction and order by columnText appended to the queryConvert to a boolean or enum and append a constant (ASC or DESC)
IN lists of variable lengthDevelopers build the list as textGenerate one placeholder per element and bind each value, or use an array parameter type
LIKE searchesWildcards in input widen the match even when boundBind the value and escape the wildcard characters, as Microsoft shows for SQL Server
JSON field names mapped to columnsKeys concatenated while values are boundAllowlist of permitted field names, mapped to fixed columns
Client-side query buildersParameterisation done in the browser or a mobile appOWASP: "ensure that query parameterization is done server-side"

As safe pseudocode, an identifier allowlist reads: define a constant map from accepted request values to column names; look up the request value; if it is missing, use the default column or return an error; insert only the mapped constant into the SQL text. Validation still has a role as a second layer: Microsoft advises testing "type, length, format, and range" at every tier, and OWASP A05:2025 calls positive server-side validation useful but "not a complete defense". Escaping is the last resort: the OWASP SQL Injection Prevention Cheat Sheet marks it "STRONGLY DISCOURAGED", and A05:2025 notes that table and column names cannot be escaped safely at all.

Stored procedures and dynamic SQL

Stored procedures protect only when they avoid building SQL from their inputs. OWASP A05:2025 warns that "Even when parameterized, stored procedures can still introduce SQL injection" if they concatenate or execute hostile data, and CWE-89 says stored procedures "do not protect against many others" attacks when built from concatenated input.

  • Find dynamic SQL: Microsoft says "You should review all code that calls EXECUTE, EXEC, or sp_executesql"; OWASP adds the equivalents on other platforms, such as EXECUTE IMMEDIATE in Oracle PL/SQL.
  • Parameterise inside the procedure: in SQL Server, pass values to sp_executesql as declared, typed parameters rather than concatenating them; in Oracle, use EXECUTE IMMEDIATE with a USING clause so values are bind variables.
  • Quote identifiers that must be dynamic: wrap names of securables in QUOTENAME and check them against sys catalogue entries or an allowlist first.
  • Size buffers: Microsoft warns that dynamic Transact-SQL assigned to a variable "is truncated if it's larger than the buffer allocated", which can cut off the quoting that protected it. Use large enough variables, or apply QUOTENAME and REPLACE directly inside the executed statement.
  • Grant execute only: OWASP notes procedures "require execute rights", and teams sometimes respond by granting db_owner. Grant EXECUTE on the specific procedures and no direct table rights.

ORM injection and SQL injection in Hibernate

Object relational mapping injection (CAPEC-109) is SQL injection one layer up. CWE-564, SQL Injection: Hibernate, a child of CWE-89, covers Hibernate executing "a dynamic SQL statement built with user-controlled input", and OWASP A05:2025 gives an HQL example that "still allows unauthorized data access when user input is concatenated into queries". ORMs parameterise their normal query methods, so ORM injection concentrates in a few places:

  • String-built query languages: HQL, JPQL and similar query strings assembled with concatenation. Use named parameters (setParameter) or the Criteria API, as OWASP's cheat sheets show.
  • Raw and native query helpers: native SQL methods, raw query and "extra" helpers, and literal fragments in query builders. Each needs bind parameters and a code review flag.
  • Dynamic field and sort names: filter and sort parameters mapped straight onto entity properties or columns. The McKinsey Lilli incident is the reference case: according to the researchers, values were parameterised but JSON field names were concatenated into SQL on one of 22 unauthenticated endpoints, and error messages that echoed the field names allowed blind refinement until production data could be read. McKinsey says it patched the endpoints within hours of the report.
  • Older or non-standard back ends: legacy applications on Microsoft Access (Jet or ACE) databases have their own SQL dialect, covered by a dedicated WSTG sub-test for MS Access, but the defence is the same: OleDbCommand parameters instead of concatenated strings, and migration off shared file-based databases for anything internet-facing.

Blind, second-order and out-of-band SQLi

These variants matter because they defeat the controls teams add after a first finding.

  • Blind SQL injection survives error suppression: CWE-89 recommends returning minimal error details, and that is right, but boolean and time-based techniques infer data from page differences and response times. Hiding errors slows an attacker; only parameterisation removes the flaw.
  • Second-order SQL injection hides in trusted data: Microsoft describes "a less direct attack" that "injects malicious code into strings that are destined for storage in a table or as metadata". Values read from your own database, such as user names, saved filters or report definitions, must be bound like request data when used in a later query. Review batch jobs, report builders and admin tools, not just input forms.
  • Out-of-band SQL injection needs a network path: it relies on the database server making DNS or other outbound connections. Default-deny egress from database servers and alert on their DNS lookups to external domains.
  • Stacked queries turn reads into writes: use drivers and settings that send one statement per call where the platform allows, and run read paths under read-only accounts so an added statement fails.

Least privilege and database hardening

CWE-89 advises: "Run your code using the lowest privileges that are required to accomplish the necessary tasks." OWASP's SQL Injection Prevention Cheat Sheet adds concrete patterns. See the Database Security Guide for platform hardening.

  • One account per application and purpose: a login or search path needs read access only; a sign-up path needs insert on specific tables. Never connect as sa, root, postgres, dbo or a db_owner member.
  • Views for narrow exposure: expose only the columns a function needs, remembering that queries against views still need parameterisation.
  • Disable dangerous features: CWE-89 notes that MS SQL includes a built-in function that executes operating system commands, which makes injection far worse; keep xp_cmdshell, OLE automation and external script execution disabled unless a reviewed use case exists.
  • Restrict the database service account: run the database engine under a low-privilege operating system account, as OWASP also advises.
  • Treat the application's database credential as a machine identity: store it in a secrets manager, rotate it, and prefer short-lived or managed identities where the platform supports them. See the Service Account Security Guide.

SQL injection detection

MITRE ATT&CK records successful exploitation as T1190 Exploit Public-Facing Application, with procedure examples that include SQL injection and a detection strategy (DET0080) that correlates web requests, application errors and server behaviour. Combine signals from three layers:

SignalSourceWhat it can indicate
SQL syntax and conversion errors from the application accountSQL Server Extended Events (error_reported), PostgreSQL log_min_error_statement, application exception logsError-based probing or a working injection point
Queries against system catalogues (information_schema, sys views) from an application accountDatabase audit logsSchema enumeration after a successful injection
Response time outliers on one routeAPM and web server logsTime-based blind SQL injection
Bursts of near-identical requests with small parameter changesWAF, API gateway and web logsBoolean blind extraction, often by an automated SQL injection tool
Outbound DNS or connections from database serversDNS resolver and firewall logsOut-of-band exfiltration
Rows returned or exported far above the route's baselineDatabase activity monitoring, application metricsBulk data theft through a working injection
New logins, permission grants or schema changes from an application accountDatabase audit logsStacked queries or escalation

Automated SQL injection tools produce distinctive volumes and request patterns, which is why WAF logs often show the first probe. Treat that as an early warning, not protection: CWE-89 rates application firewalls as moderate, and the McKinsey case shows a flaw in JSON keys that standard scanners reportedly missed. Send all of it to the SIEM; see the SIEM Guide.

Testing and code review

  • Static analysis with taint tracking: CWE-89 rates source code analysers and manual source review as high effectiveness, with the caveat that tools miss custom or third-party SQL APIs. Configure rules for your data access layer, ORM raw helpers and stored procedure calls.
  • Dynamic testing: CWE-89 rates database and web application scanners as highly effective. Run them against staging with every API, including JSON and GraphQL bodies and authenticated routes.
  • Structured manual tests: use WSTG-INPV-05 and its sub-tests for Oracle, MySQL, SQL Server, PostgreSQL, MS Access, NoSQL, ORM injection and client-side injection, and include second-order paths by following stored data into batch jobs and admin features.
  • Reviewer questions: is any SQL text built from variables? Are identifiers mapped from an allowlist? Does any procedure call EXEC or EXECUTE IMMEDIATE? Which account does this path use, and can it write?

Rollout and decision guidance

  1. Inventory data access: list applications, databases, connection accounts and their rights; flag internet-facing and unauthenticated routes first.
  2. Find string-built SQL: run static analysis and search for concatenated queries, raw ORM helpers and dynamic SQL in procedures; rank by exposure.
  3. Fix by pattern in shared code: a data access layer that only accepts parameters, an identifier allowlist helper and a reviewed list of permitted raw queries.
  4. Cut privileges in a pilot: move one application to per-purpose accounts and execute-only rights, run its regression suite, and keep the old grants scripted so they can be restored quickly if a path breaks.
  5. Lock down the database host: disable command execution features and default-deny egress, logging first so legitimate flows are found.
  6. Turn on detection: database error and audit logging to the SIEM, with alerts tuned in monitoring mode for two to four weeks before paging.
  7. Gate releases: block new string-built SQL in pull requests and accept releases against ASVS 5.0 requirement 1.2.4 (parameterised queries, ORMs or equivalent, including in stored procedures).
  • ORM or hand-written SQL: OWASP suggests an ORM for new applications; keep hand-written SQL for performance-critical paths, behind the shared parameterised layer.
  • Stored procedures or prepared statements: both are safe when written correctly; choose by team skills and change process, not security.
  • Code fix or WAF: fix code you own; use WAF virtual patching for third-party products only until the vendor ships a fix. See the Web Application Firewall Guide.
  • Small versus large organisations: small teams should use the framework ORM, a lint rule against string-built SQL and a managed database with least-privilege roles; large ones need a paved-road data layer, central database audit logging and findings tracked by CWE-89 across the portfolio.

Metrics: string-built SQL findings open and median time to fix; share of applications on the approved data layer; share of application database accounts with no owner or DBA rights; share of database servers with default-deny egress; repeat SQLi findings in the same application within 12 months.

Framework mapping

FrameworkReferenceRelevance
OWASP Top 10:2025A05:2025 InjectionCWE-89 and CWE-564 are notable CWEs
OWASP ASVS 5.0V1.2.4Parameterised queries, ORMs or equivalent, including in stored procedures
MITRE CWE and CAPECCWE-89 (child of CWE-943); CWE-564; CAPEC-66, CAPEC-109Weakness and attack pattern tagging
NIST SP 800-53 Rev. 5SI-10, AC-6, SA-11, AU-12Input validation, least privilege, developer testing, audit records
CIS Controls v8.116.1, 16.12, Control 5 and 6Secure development, code-level checks, account and access management
ISO/IEC 27001:2022 Annex AA.8.28, A.8.29, A.8.2Secure coding, security testing, privileged access rights
MITRE ATT&CK v20T1190; M1026 Privileged Account Management; M1030 Network SegmentationExploitation of public-facing applications and the matching mitigations

Common failure patterns

  • Escaping instead of binding: CISA and the FBI call sanitisation brittle; the MOVEit campaign they referenced affected thousands of organisations.
  • Parameterised values, concatenated identifiers: sort, filter and JSON field names left out of the fix, as in the McKinsey Lilli case.
  • "We use stored procedures": procedures that build dynamic SQL with EXEC, assumed safe because they are procedures.
  • Raw ORM helpers as shortcuts: one native query added for performance becomes the injectable path.
  • Hiding errors and calling it fixed: blind and time-based techniques still work.
  • Application accounts with owner rights: one injection becomes full database compromise, schema changes and, with command execution features on, a host foothold.

Practitioner checklist

  • Bind every value with the platform's parameter API; ban string-built SQL with a lint rule and SAST.
  • Map identifiers, sort fields and JSON field names through allowlists; never concatenate them.
  • Review every EXEC, sp_executesql and EXECUTE IMMEDIATE; pass values as typed parameters and wrap identifiers in QUOTENAME.
  • Use named parameters or the Criteria API in Hibernate and flag every raw or native ORM query.
  • Treat data read from your own database as untrusted when it feeds another query.
  • Give each application per-purpose database accounts with no owner or DBA rights and execute-only grants on procedures.
  • Disable database command execution features and default-deny egress from database servers.
  • Log database errors and catalogue queries to the SIEM and alert on application-account anomalies.
  • Test with WSTG-INPV-05 and its sub-tests, including authenticated, JSON and second-order paths.
  • Track SQLi findings, time to fix and recurrence by application.

Standards and references

Related NHI Mgmt Group resources: Web Application Attacks Guide · Secure Coding Guide · Database Security Guide · Service Account Security Guide · Web Application Firewall Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 18 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org