Why generated code keeps doing this
String interpolation is the most direct way to get a value into a query, and the most direct version is what code generators reach for — especially because decades of tutorials, Stack Overflow answers, and example snippets in their training data do exactly this. The insecure version isn't an exotic failure; it's the statistically typical way the operation gets written.
It also survives because it's invisible to the vibe-coding feedback loop. An injectable query behaves identically to a safe one on every normal input; the difference only appears when someone sends a crafted one — a quote, a UNION SELECT, a stacked statement. "It works" tells you nothing here, which is why this bug ships so often.
How to spot it in your own repo
The tell is a variable inside a query string. In Python: an f-string with a brace inside SQL (f"SELECT * FROM users WHERE email = '{email}'"), .format() on a query, or % formatting and + concatenation building SQL. In JavaScript and TypeScript: a template literal with ${} inside a query, or strings glued together with +. If user input can reach that variable — a form field, a URL parameter, a JSON body — the query is injectable.
The parameterised fix has the same shape everywhere: a placeholder in the query, the value passed separately, so the database driver treats input as data rather than executable SQL. Python's drivers use %s or ? with a parameters tuple; node-postgres uses $1 with a values array; and if you're on an ORM like SQLAlchemy or Prisma, you're safe by default unless you've dropped into raw-SQL escape hatches with interpolation — which is exactly where generated code sometimes ends up.
Fixing every instance, not just the one you found
The dangerous failure mode is fixing the query you noticed and missing the four others written the same way — a codebase that built SQL with strings once almost always did it repeatedly. This is why a systematic pass beats spot-fixing, and why securevibes scans the whole repo: its injection checks flag SQL built with f-strings, .format(), concatenation, or template literals, alongside the neighbouring hazards (eval/exec, shell commands built from variables, subprocess shell=True, pickle, unsafe yaml.load, innerHTML and dangerouslySetInnerHTML).
Each finding lands with the file, the line, why it matters, the parameterised fix — and a ready-to-paste Claude prompt that includes the constraint "check for the same pattern elsewhere", so the agent that introduced the pattern hunts down every instance of it rather than patching one line. Worth saying plainly: this is pattern detection, not proof of exploitability; securevibes doesn't execute your code, so treat every flagged query as worth converting rather than waiting for certainty.
String-built (injectable) vs parameterised, per language
| Language / stack | Injectable pattern to look for | Parameterised fix |
|---|---|---|
| Python (DB-API drivers) | f"...WHERE email = '{email}'", .format(), % or + building SQL | cursor.execute("...WHERE email = %s", (email,)) — or ? depending on driver |
| JavaScript / TypeScript | `...WHERE id = ${id}` template literals, + concatenation | query("...WHERE id = $1", [id]) with node-postgres or equivalent |
| ORMs (SQLAlchemy, Prisma...) | Raw-SQL escape hatches with interpolated strings | Stay on ORM query methods; pass bound parameters in raw queries |
frequently asked
- My inputs come from my own frontend — am I still at risk?
- Yes. Attackers don't use your frontend; they send requests directly to your API. Any string-built query reachable from a request is injectable regardless of what your UI allows.
- Is escaping or sanitising the input enough?
- Parameterised queries are the reliable fix — the driver keeps data and SQL separate by construction. Hand-rolled escaping is exactly the kind of subtle, easy-to-get-wrong code you don't want, especially in a codebase you didn't write line-by-line yourself.
- I use an ORM — can I skip this check?
- Mostly safe, with one caveat: raw-SQL escape hatches. Generated code sometimes drops out of the ORM into a raw query with interpolation, which reintroduces the problem. A scan catches those spots.
- How does securevibes report an injection finding?
- With the severity, the file and line, the evidence, why it matters, the parameterised fix, and a paste-ready Claude prompt that includes "check for the same pattern elsewhere" — because string-built SQL almost never appears just once.
Published June 10, 2026 · Last updated June 11, 2026