SQL Injection Without Myths: How to Find and Fix It in a Project
A practical SQL injection guide: how the attack works, where to find it in code, which language and framework patterns create risk, how to test a project, and which tools and libraries help prevent it.

Imagine a product search. The application wants to run SELECT * FROM products WHERE name = ?. With a parameter, the database receives the query template and the value separately. When a developer manually concatenates a string, input can change the WHERE structure, add another condition, or terminate the command.
The user controls a value
It may be a query string, JSON body, cookie, header, CSV import, webhook, sort parameter, or queue message. If an external party can change its source, treat it as untrusted.
The value is joined to SQL
The risk appears in query = '... ' + input + ' ...', a template string, a raw query builder, or an ORM method that accepts finished SQL. Format validation does not replace parameterization.
The database sees syntax, not data
Special characters and SQL fragments may change a condition, combine results, affect response timing, or turn a read into a write operation, depending on the driver and permissions.
The flaw reaches beyond one endpoint
If a connection user has excessive permissions, one compromised endpoint can expose tables, reports, personal data, backups, or another tenant's records.
Mental model
Do not ask only whether the project uses an ORM. Ask whether external input can affect SQL structure and which privileges execute the query.
Read these numbers carefully. OWASP measures the broad Injection category, which includes SQLi, XSS, and other CWEs. MITRE scores CWE-89 from CVE data. This is not a percentage of all attacks and not a ranking of programming languages.
274,228
total occurrences for the Injection category in the OWASP dataset; average incidence rate was 3.37%. [2]
#2
SQL Injection ranked second in MITRE's 2025 CWE Top 25, with a score of 28.72. [3]
94%
of applications in the study were tested for some form of injection. [2]
What this means for a team
SQLi is a mature, well-described problem, but maturity does not make legacy code safe. Its repeatable patterns are useful for defense: they can be checked with static analysis and tests.
Start with the data flow, not a framework list: identify the external source, follow it into the data-access layer, and inspect the actual driver call.
Find dangerous sinks
Search for query, execute, raw, text, literal, sequelize.query, knex.raw, jdbc.Statement, SqlCommand, and equivalents. Check whether they receive a concatenated string.
Review dynamic SQL
Pay special attention to ORDER BY, column/table names, report builders, and filters. Bind variables often cannot represent identifiers; use an allow-list mapping from fixed values instead. [1]
Inspect ORM escape hatches
Review raw SQL, unsafe operators, custom scopes, string filters, and migrations. An ORM lowers risk only when the team stays on its parameterized APIs.
Include non-obvious entry points
Admin panels, imports, cron jobs, integrations, GraphQL resolvers, search endpoints, and internal APIs also process data that may have been compromised earlier in the chain.
Check error handling
SQL stack traces, table names, driver details, or different errors for different conditions make attacks easier to diagnose. Return a safe public error and keep details in correlation-ID logs.
There is no honest ranking of the most dangerous language: SQLi is possible anywhere SQL meets an unsafe API. The difference is how easy it is to accidentally leave the parameterized path for raw SQL.
| Ecosystem | Typical risk point | Safer default | What to review |
|---|---|---|---|
| PHP: Laravel / Symfony | DB::raw, query strings, old mysqli/PDO code | Query Builder/Eloquent bindings, PDO prepared statements | raw(), bound parameters, legacy controllers |
| JavaScript / TypeScript: Node.js | pg/mysql2 template strings, knex.raw, Sequelize raw | driver placeholders, Prisma parameters, query builders | $queryRawUnsafe, raw(), dynamic filters |
| Python: Django / SQLAlchemy | cursor.execute concatenation, text() with a string | Django QuerySet, SQLAlchemy bound parameters | extra(), raw(), literal SQL, f-strings |
| Java: Spring / Hibernate | Statement, string concatenation, HQL interpolation | PreparedStatement, JPA parameters, named parameters | createNativeQuery, HQL interpolation |
| .NET: ASP.NET / EF Core | FromSqlRaw or SqlCommand with a string | LINQ, FromSqlInterpolated, parameters | raw methods, interpolated SQL, database role |
| Go / Rust | database/sql or client APIs with string building | QueryContext/Execute placeholders, sqlx bind | fmt.Sprintf, format!, dynamic identifiers |
The stack-level conclusion
The largest risk comes not from a language, but from teams that mix input with query text, allow raw SQL without review, or give the application a DBA role.
Unsafe: the string knows too much
const sql = `SELECT * FROM users WHERE email = '${email}'`;
const result = await db.query(sql);Here email becomes part of the SQL text. Even if this starts as a search, the pattern is easily copied into login, export, or admin features.
Safer: the driver separates values
const result = await db.query(
"SELECT * FROM users WHERE email = $1",
[email],
);The query text is fixed and email is passed as a value. Placeholder syntax differs between drivers, so follow your client library's documentation.
For sort fields, use a mapping
const columns = { newest: "created_at", price: "price" } as const;
const column = columns[input] ?? columns.newest;
const sql = `SELECT * FROM products ORDER BY ${column}`;Column names are not ordinary bind values. Allow only keys from a fixed list and never insert raw input directly.
No single tool sees the whole picture. The strongest workflow combines code analysis, endpoint testing, and runtime observation.
CodeQL
SAST for tracing data from user input to SQL sinks in JavaScript/TypeScript, Python, Java, C# and other supported languages. Add it to CI and review findings with the code owner.
Semgrep
Fast pattern and data-flow rules for local checks and pre-commit. Use it to ban specific unsafe calls such as raw queries without parameters.
Burp Suite / OWASP ZAP
DAST for staging: proxying, request replay, and active or passive scanning. Use an approved scope and never enable destructive checks against production.
PortSwigger Web Security Academy
A safe training environment with SQLi labs covering error-based, blind, UNION, and other scenarios. It lets a team practice without touching customer data.
Sentry / DB audit logs / WAF
Look for unusual 4xx/5xx spikes, latency, SQL parser errors, mass SELECTs, odd user agents, and access to unusual tables. A WAF is a risk-reduction layer, not a code patch.
OWASP recommends more than one filter. Build a defense-in-depth baseline and make it part of the Definition of Done.
Use parameterized queries or safe stored procedures; dynamic SQL needs an allow-list and a separate review. [1]
Do not rely on escaping as the primary defense: OWASP calls it fragile and recommends it only as a last resort for legacy code. [1]
Use a dedicated application database user with minimum SELECT/INSERT/UPDATE permissions, never a DBA/owner role. Use read-only accounts or views for read-only flows. [1]
Do not put secrets or production data in logs. Record endpoint, actor, request ID, and policy result, not full SQL with personal parameters.
Add negative tests: quotes in legitimate names, long strings, Unicode, wrong types, unknown sort keys, cross-tenant IDs, and boundary values.
Keep the driver, ORM, and database engine patched, but do not treat dependency updates as a replacement for safe query construction.
First hour
Stop the damage from spreading
Capture the endpoint, time, request ID, and scope. If needed, disable the feature, restrict the route, or reduce the database role to read-only. Do not delete logs or experiment on production.
Same day
Fix the root cause
Replace string-built SQL with a parameterized API, add allow-list mapping for identifiers, review database permissions, and write a regression test that fails against the old implementation.
After the patch
Check the blast radius
Review database audit logs, unusual exports, data changes, service accounts, and access to other tenants. Record what may have been read or changed.
Before closing
Improve the process
Add SAST/DAST to CI, a review rule for raw queries, a least-privilege migration, and a short incident playbook. Otherwise the next SQLi will appear in another endpoint.
ORMs usually parameterize standard queries, but they do not automatically protect raw SQL, unsafe operators, dynamic identifiers, or custom query builders. Review escape hatches and team rules.
Format validation helps, but it is not a universal defense. Use parameterized queries for values and fixed allow-list mappings for table names, column names, and sorting.
Yes. GraphQL changes the API shape, but a resolver can still pass an argument into unsafe SQL, a filter, or a raw query. Trace data flow from resolver arguments to the database client.
A WAF can block known patterns and reduce exploitation, but it does not fix query construction or guarantee coverage of obfuscation and business-specific paths. Patch, least privilege, and tests remain necessary.
Use a local sandbox, OWASP Juice Shop, WebGoat, or PortSwigger Academy. Never test a third-party site, client API, or production system without an explicitly approved scope.
PAS7 Studio can review your API, admin panel, and data-access layer: find raw SQL, check tenant boundaries, configure SAST/DAST in CI, reduce database permissions, and prepare a prioritized remediation plan.
Related Articles
AI Assistant Development Cost in 2026: RAG Chatbots, CRM Integrations, Guardrails, and Support
A practical buyer guide to AI assistant development cost in 2026: prototypes, RAG chatbots, knowledge-base assistants, CRM and website integrations, guardrails, evaluations, monitoring, and support.
AI-assisted attacks and prompt injection in 2026: the new attack surface for AI products
AI-assisted attacks and prompt injection in 2026: the new attack surface for AI products. A practical PAS7 Studio security guide with threat model, controls, rollout checklist, pitfalls, and sources.
AI for landing page development: where it speeds up launches and where it hurts conversion
A practical research piece on using AI for landing page development: v0, Webflow AI, Builder.io, Framer-like builders, UX generation, copy, SEO, personalization, A/B testing, template risk, accessibility, security and technical debt.
AI SEO / GEO in 2026: Your Next Customers Aren’t Humans — They’re Agents
Search is shifting from clicks to answers. Bots and AI agents crawl, cite, recommend, and increasingly buy. Learn what AI SEO / GEO means, why classic SEO is no longer enough, and how PAS7 Studio helps brands win visibility in the agentic web.
Professional development for your business
We create modern web solutions and bots for businesses. Learn how we can help you achieve your goals.