SQL injection explained with a login form
One of the oldest web attacks, still found in scans every week. How a login form becomes a way in, why it works, and the one habit that closes it for good.
The short answer
A website asks its database questions in a language called SQL. When the code builds those questions by gluing in whatever a visitor typed, a visitor can type something that changes the question itself. That is SQL injection. The oldest example is a login form that lets anyone in as any user; the same technique reads customer records, changes prices or deletes tables. It is one of the oldest web attacks and it still turns up in scans every week.
The fix has been standard for decades. It is a habit, and the habit is what old code and hasty plugins skip.
Why it works
The unsafe code takes the visitor’s text and pastes it into the middle of the query. If the text contains the characters that SQL uses for structure, quotes, comment markers, keywords, the database reads them as structure. A username like admin' OR '1'='1 closes the name early and adds a condition that is always true, so the query matches every user. A more hostile input reads other tables or drops them.
The safe code never pastes. It sends a query with a fixed shape and the input as separate values. Whatever the visitor typed is, to the database, just a string to compare against names. It can be as strange as it likes; it cannot become part of the question.
Where it still lives
| Place | Why |
|---|---|
| Older custom code | Written before the habit was universal, never revisited |
| Plugins and extensions | Some build queries by hand; popularity does not mean review |
| The one quick feature | A developer bypassed the framework’s safe path “just for this report” |
| Search and filter endpoints | Many parameters, often added in a hurry |
| Legacy admin tools | Internal, so nobody scanned them, and reachable anyway |
What to do
- Scan. A security scan probes forms and parameters for injection patterns. It is the fastest way to find the obvious cases.
- Review anything that talks to a database. Every function, plugin and endpoint. The question is one: fixed-shape queries with values passed separately, or strings glued together?
- Fix by habit, not by filtering. Filtering dangerous characters is a losing game. Parameterised queries close the problem at the root.
- Limit the damage. The database account the site uses should be able to do only what the site needs. A read-only site does not need permission to delete tables.
- Reduce the surface. A static site with a few small functions has very little to review. That is the design advantage, and it is real.
What this means for you
SQL injection is old, well understood and entirely preventable, which makes finding it on a business site a statement about how the site was built and maintained. Run a scan, have everything that touches the database reviewed for the one habit, and give the site’s database account the least it needs. On a static site that is an hour of work, and then it stays done.
Frequently asked questions
Is this still a real risk in 2026?
Yes, mostly in older code, plugins and hand-written database calls. Modern frameworks make the safe way the default, so new code rarely has it. Scans still find it regularly on sites with an ageing plugin stack or custom code written without the habit.
Does a static site have this problem?
The pages do not; there is no database behind them. Any function that does talk to a database, a form handler, a search endpoint, an integration, can, if it builds queries by hand. The surface is small and easy to check, which is one of the advantages.
How do we check our site?
A scan probes forms and parameters for the classic patterns and reports what it finds. A code review of anything that talks to a database confirms whether queries are parameterised. For a business website both take an hour.
Sources
- OWASP Cheat Sheet: SQL Injection Prevention (accessed 2026-09-11)
- OWASP Top Ten (accessed 2026-09-11)