Quick Answer
SQL injection happens when user input is inserted directly into a database query string instead of being passed as a parameter. AI code generators like Bolt, Lovable, and Cursor produce SQL injection vulnerabilities at 2.74x the rate of human-written code. The fix is simple: always use parameterized queries or an ORM.
What Is SQL Injection and Why Should You Care?
SQL injection (SQLi) is one of the oldest and most dangerous web vulnerabilities. It's been in the OWASP Top 10 every year since the list was created. In 2023, the Apiiro research team found that AI-generated code contains 2.74x more vulnerabilities than human-written code - and SQL injection is the most common one.
Here's why it matters: a single SQL injection vulnerability lets an attacker read your entire database, modify data, delete tables, or even execute system commands. If your vibe-coded app handles user data, payment info, or authentication - one vulnerable query is all it takes.
According to Veracode's 2023 State of Software Security report, 26% of applications have SQL injection flaws. For AI-generated applications built with tools like Bolt, Lovable, Cursor, or v0, that number is significantly higher because AI models optimize for working code, not secure code.
How AI Code Generators Create SQL Injection Vulnerabilities
When you prompt an AI tool to "build a user search endpoint," it often generates the fastest working solution - which means string interpolation in SQL queries. The AI doesn't think about security; it thinks about satisfying your prompt.
Here's a real example of what Bolt or Cursor might generate:
// ❌ BAD - SQL Injection Vulnerability
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const result = await db.query(
`SELECT * FROM users WHERE name = '${search}'`
);
res.json(result.rows);
});
This looks fine. It works. But an attacker can send search='; DROP TABLE users; -- and destroy your entire users table. Other attack patterns include ' OR '1'='1 to bypass authentication, or ' UNION SELECT password FROM admin -- to extract sensitive data from other tables.
These patterns are caught by VibeDoctor's SEC-002 check, which scans for 6 different string interpolation patterns in database queries across JavaScript, TypeScript, Python, and SQL files.
The 6 SQL Injection Patterns AI Code Gets Wrong
| Pattern | Example | Risk Level |
|---|---|---|
| Template literal in query | `SELECT * FROM users WHERE id = ${id}` |
Critical |
| String concatenation | "SELECT * FROM users WHERE id = " + id |
Critical |
| f-string in Python | f"SELECT * FROM users WHERE id = {id}" |
Critical |
| format() in Python | "SELECT ... WHERE id = {}".format(id) |
Critical |
| % formatting in Python | "SELECT ... WHERE id = %s" % id |
Critical |
| Raw SQL in ORM | prisma.$queryRaw(`SELECT ... ${id}`) |
Critical |
What Does Safe Code Look Like?
The fix is always the same: parameterized queries. Instead of inserting values into the SQL string, you pass them as separate parameters that the database driver safely escapes.
// ✅ GOOD - Parameterized Query (pg library)
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const result = await db.query(
'SELECT * FROM users WHERE name = $1',
[search]
);
res.json(result.rows);
});
// ✅ GOOD - Using an ORM (Prisma)
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const users = await prisma.user.findMany({
where: { name: search }
});
res.json(users);
});
// ✅ GOOD - Using Drizzle ORM
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const users = await db
.select()
.from(usersTable)
.where(eq(usersTable.name, search));
res.json(users);
});
With parameterized queries, even if an attacker sends '; DROP TABLE users; --, it's treated as a literal string value - not as SQL code. The database engine knows the difference between data and commands.
Frameworks That Help (And Ones That Don't)
If you're using an ORM like Prisma, Drizzle, or Sequelize, you're mostly safe - as long as you use the ORM's query builder and don't drop down to raw SQL. The danger zone is when AI tools use prisma.$queryRaw() or sequelize.query() with string interpolation.
Supabase's JavaScript client is also safe for standard operations like .from('users').select('*').eq('name', search). But AI tools sometimes generate the Supabase .rpc() call with string-interpolated function parameters - which brings the vulnerability back.
A study by the Cloud Security Alliance (CSA) in 2024 found that 40% of AI-generated database code contained at least one unsafe query pattern, even when using an ORM, because AI falls back to raw SQL for complex queries.
How to Find and Fix SQL Injection in Your Codebase
Here's a practical checklist:
- Search your codebase for
$queryRaw,.query(`,db.execute(`, andsequelize.query(. Any template literal or string concatenation in these calls is a red flag. - Use parameterized queries everywhere. If your ORM supports it, stick to the query builder. For raw SQL, use
$1, $2placeholders (PostgreSQL) or?(MySQL). - Add input validation with Zod or Joi at the API route level. Even with parameterized queries, validation ensures only expected data types reach your database.
- Run automated scanning. Tools like VibeDoctor (vibedoctor.io) automatically scan your codebase for SQL injection patterns and flag the exact file paths and line numbers. It's free to sign up and takes under 5 minutes.
- Review AI-generated database code manually. Every query that touches user input deserves a second look.
FAQ
Can SQL injection happen with Prisma or Drizzle?
Not with standard query builder methods. But if AI generates prisma.$queryRaw() or prisma.$executeRaw() with template literals, yes - those are vulnerable. Use Prisma.sql tagged template for safe raw queries.
Does Supabase protect against SQL injection?
Supabase's JavaScript client auto-parameterizes standard queries. But custom RPC calls and raw PostgREST filters can still be vulnerable if you concatenate user input.
How common is SQL injection in AI-generated code?
According to Apiiro's 2023 research, AI-generated code has 2.74x more vulnerabilities than human code. SQL injection is the #1 injection-type vulnerability found. The CSA reports 40% of AI-generated database code has at least one unsafe query.
Is this only a backend problem?
SQL injection is a server-side vulnerability. But if your Bolt or Lovable app uses Supabase with direct client-side database access and RLS policies aren't configured, the risk extends to the frontend too.
What tools can detect SQL injection automatically?
VibeDoctor's SEC-002 check scans 6 injection patterns. SonarQube, Semgrep, and ESLint security plugins also catch common patterns. For the most thorough check, combine static analysis with a tool like Trivy for dependency-level vulnerabilities.