← All posts
prevent sql injection ai codesql injection preventionAI-generated code securityvibe coding securityOWASP Top 10

Prevent SQL Injection in AI Code: A Practical Guide

O

OverMCP Team

TL;DR: To prevent SQL injection in AI-generated code, never trust user input directly in SQL queries. Always use parameterized queries or prepared statements, validate and sanitize all inputs, and apply the principle of least privilege to database accounts. These practices work regardless of whether the code was written by an AI or a human.

Why AI-Generated Code Is Prone to SQL Injection

AI coding assistants like Cursor, Bolt.new, and Replit Agent are trained on vast amounts of public code, including insecure examples. They often generate code that works but lacks security best practices. For instance, an AI might produce a simple SELECT query using string concatenation because that's common in tutorials. This is exactly the pattern that leads to SQL injection.

Consider this AI-generated Node.js/Express code:

app.get('/user', (req, res) => {
  const id = req.query.id;
  const query = `SELECT * FROM users WHERE id = ${id}`;
  db.query(query, (err, result) => {
    res.json(result);
  });
});

This is vulnerable. An attacker could pass id=1 OR 1=1 to retrieve all users, or worse, id=1; DROP TABLE users-- to delete your data.

How to Prevent SQL Injection in AI Code: Step-by-Step

1. Use Parameterized Queries (Prepared Statements)

Parameterized queries separate SQL logic from data. The database engine treats parameters as data, not executable code. Here's the fixed version:

app.get('/user', (req, res) => {
  const id = req.query.id;
  const query = 'SELECT * FROM users WHERE id = ?';
  db.query(query, [id], (err, result) => {
    res.json(result);
  });
});

The ? placeholder ensures id is always treated as a value, never as part of the SQL command.

In Python (with psycopg2):

import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()
cur.execute("SELECT * FROM users WHERE id = %s", (user_id,))

In Python (with SQLite3):

import sqlite3
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))

In Java (JDBC):

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
stmt.setInt(1, userId);
ResultSet rs = stmt.executeQuery();

In PHP (PDO):

$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $userId]);

2. Validate and Sanitize Input

Even with parameterized queries, you should validate inputs to ensure they match expected types and formats. For example:

// Validate that id is a positive integer
const id = parseInt(req.query.id, 10);
if (isNaN(id) || id < 0) {
  return res.status(400).json({ error: 'Invalid ID' });
}

For strings, use allowlists or reject known dangerous patterns. But remember: validation is a second layer, not a replacement for parameterization.

3. Use an ORM (Object-Relational Mapping)

ORMs like Prisma, Sequelize (Node.js), SQLAlchemy (Python), or Hibernate (Java) automatically use parameterized queries. They also reduce the chance of injection because you rarely write raw SQL.

Example with Prisma:

const user = await prisma.user.findUnique({
  where: { id: parseInt(id) }
});

But beware: ORMs can still be misused. Some allow raw queries or dynamic filters that might introduce injection if not handled carefully.

4. Apply Least Privilege to Database Accounts

Your application's database user should have only the necessary permissions. For example, if the app only reads from the users table, grant only SELECT on that table, not INSERT, UPDATE, DELETE, or DROP. This limits damage if an injection occurs.

-- Create a read-only user for the app
CREATE USER app_user WITH PASSWORD 'strong_password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_user;

5. Use a Security Scanner for AI-Generated Code

AI-generated code often hides subtle vulnerabilities. A tool like OverMCP can scan your codebase for SQL injection patterns, hardcoded secrets, and other OWASP Top 10 issues before you deploy. It's specifically designed for vibe-coded apps where speed meets security.

Real-World Example: Fixing an AI-Generated Login

Here's a vulnerable login endpoint an AI might produce:

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    cursor.execute(query)
    user = cursor.fetchone()
    if user:
        return "Login successful"
    else:
        return "Invalid credentials"

Attack: username = admin' -- bypasses password check.

Fixed version:

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    query = "SELECT * FROM users WHERE username = ? AND password = ?"
    cursor.execute(query, (username, password))
    user = cursor.fetchone()
    if user:
        return "Login successful"
    else:
        return "Invalid credentials"

Common Mistakes in AI-Generated Code

  • Using string formatting/f-strings for SQL queries (e.g., f"SELECT ... WHERE id = {id}")
  • Escaping quotes manually (e.g., replacing ' with \') — this is unreliable and can be bypassed
  • Using `eval()` or `exec()` with user input
  • Storing raw SQL in configuration files that get concatenated
  • Forgetting to parameterize `LIKE` clauses — still possible with % placeholders
  • FAQ

    What is the most effective way to prevent SQL injection in AI-generated code?

    The most effective way is to always use parameterized queries (prepared statements). This ensures user input is never treated as executable SQL. Combined with input validation and least privilege, it eliminates the risk.

    Can an ORM completely prevent SQL injection?

    No, an ORM reduces risk but doesn't guarantee safety. If you use raw SQL queries within an ORM (e.g., sequelize.query() or prisma.$queryRawUnsafe()), you can still introduce injection. Always parameterize any raw queries.

    How do I scan my AI-generated code for SQL injection vulnerabilities?

    Use a security scanning tool like OverMCP, which automatically detects SQL injection patterns, hardcoded secrets, and other vulnerabilities in your codebase. It's designed for apps built with AI coding assistants and integrates with your CI/CD pipeline.

    Conclusion

    SQL injection is one of the oldest and most dangerous web vulnerabilities, but it's also one of the easiest to prevent. When using AI to generate code, always double-check that every database query uses parameterized statements. Validate inputs, apply least privilege, and run a security scanner before deployment. By following these practices, you can ship fast with AI without sacrificing security.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free