← All Articles 🔒 Security Vulnerabilities Critical By Nishant Kumar Verma Updated

SQL Injection in AI-Generated Code: The Hidden Risk of Vibe Coding

AI tools like Bolt and Cursor generate SQL injection vulnerabilities 2.74x more often. Learn to spot and fix string interpolation in database queries.

SEC-002

Quick Answer

SQL injection happens when user input is inserted directly into a database query string instead of being passed as a parameter. CodeRabbit's analysis of 470 open-source pull requests found security issues up to 2.74x higher in AI-co-authored code than in 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. Injection, the category it belongs to, is still in the OWASP Top 10 as A05 in the 2025 list. CodeRabbit's December 2025 analysis found security issues up to 2.74x higher in AI co-authored pull requests than in human-only ones.

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 State of Software Security 2023, 22.5% of applications scanned with static analysis had SQL injection flaws. Apps built with tools like Bolt, Lovable, Cursor, or v0 are not immune, 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. In JavaScript and TypeScript it flags template literals and string concatenation passed to query(), execute(), raw(), and Knex's whereRaw()-style methods. In Python it flags f-strings, % formatting, .format(), and concatenation in cursor.execute(), SQLAlchemy text(), and Django raw() calls.

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.$queryRawUnsafe(`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 driver sends to the database apart from the SQL text, and the database substitutes them safely.

// ✅ 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.$queryRawUnsafe() or sequelize.query() with string interpolation. Prisma's tagged prisma.$queryRaw`...` form is parameterized and safe.

Supabase's JavaScript client is also safe for standard operations like .from('users').select('*').eq('name', search). Two places still need care. The filter string you pass to .or() is used as-is in PostgREST syntax, and Supabase's docs tell you to sanitize it. And a Postgres function you call with .rpc() is only as safe as its own SQL: if it builds a query by concatenating its arguments and runs it with EXECUTE, user input can become SQL again (pass values with USING instead).

Even in projects that use an ORM, AI tools can fall back to raw SQL for complex queries, which is where string-built queries tend to appear.

For Prisma specifically, our guide to raw query injection in Prisma shows the difference between the safe tagged-template form of $queryRaw and the unsafe string form.

How to Find and Fix SQL Injection in Your Codebase

Here's a practical checklist:

  1. Search your codebase for $queryRawUnsafe, $executeRawUnsafe, .query(`, db.execute(`, and sequelize.query(. Any template literal or string concatenation in these calls is a red flag.
  2. Use parameterized queries everywhere. If your ORM supports it, stick to the query builder. For raw SQL, use $1, $2 placeholders (PostgreSQL) or ? (MySQL).
  3. 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.
  4. Run automated scanning. Tools like VibeDoctor's Vibe Check automatically scan your codebase for SQL injection patterns and flag the exact file paths and line numbers. It's free to sign up.
  5. 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. Prisma's tagged $queryRaw`...` and $executeRaw`...` also turn variables into parameters. But if AI generates prisma.$queryRawUnsafe() or prisma.$executeRawUnsafe() with template literals or string concatenation, yes - those are vulnerable. Use the tagged form or the Prisma.sql helper for safe raw queries.

Does Supabase protect against SQL injection?

Supabase's JavaScript client auto-parameterizes standard queries. But .or() filter strings are passed through as raw PostgREST syntax, and a database function called with .rpc() can still build unsafe SQL inside itself, so neither should contain concatenated user input.

How common is SQL injection in AI-generated code?

CodeRabbit's State of AI vs Human Code Generation Report (December 2025) found security issues up to 2.74x higher in AI co-authored pull requests than in human-only ones. The report does not break that figure down by vulnerability type, so treat every AI-written query that touches user input as suspect.

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 flags string-built SQL in JavaScript, TypeScript, and Python. 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.

Diagnose your codebase - free

VibeDoctor checks for SEC-002 and 148 other issues across 21 diagnostic areas - security, performance, code quality, and more.

SCAN MY APP →