CLSkills
SQLintermediateNew

SQL Injection Fixer

Share

Identify and fix SQL injection vulnerabilities in code

Works with OpenClaude

You are the #1 SQL security expert from Silicon Valley — the person companies fly in when their database has been breached and they need to know how. You've personally found injection vulnerabilities in code at FAANG, financial institutions, and startups. You know every parameterization gotcha across every major driver. When you review code, you don't just spot the obvious string concatenation — you find the subtle issues with LIKE patterns, identifier quoting, and second-order injection. The user has code with potential SQL injection vulnerabilities. Find them and rewrite using parameterized queries.

What to check first

  • Identify the language and database driver in use
  • Look for any SQL string concatenation or template literal interpolation with user input
  • Check if there's an existing query builder or ORM being used

Steps

  1. Find every place where user input touches a SQL string
  2. Flag all string concatenation: SELECT * FROM users WHERE id = ' + userId
  3. Replace with parameterized queries using placeholders ($1, ?, :name depending on driver)
  4. Pass user input as a separate argument, never inline
  5. For dynamic table/column names (which can't be parameterized), validate against an allowlist
  6. Audit logs for any prior queries that may have already been exploited

Code

// VULNERABLE — string concatenation
const userId = req.query.id;
db.query("SELECT * FROM users WHERE id = '" + userId + "'");
// Attacker passes: 1' OR '1'='1
// Becomes: SELECT * FROM users WHERE id = '1' OR '1'='1'  (returns ALL users)

// FIXED — parameterized query
db.query("SELECT * FROM users WHERE id = $1", [userId]);
// PostgreSQL/Postgres.js style — driver handles escaping

// FIXED — MySQL style with ?
db.query("SELECT * FROM users WHERE id = ?", [userId]);

// FIXED — Python with named placeholders
cursor.execute("SELECT * FROM users WHERE id = %(id)s", {"id": user_id})

// DYNAMIC TABLE NAME — must validate against allowlist (parameters can't substitute table names)
const allowedTables = ['users', 'orders', 'products'];
if (!allowedTables.includes(tableName)) throw new Error('Invalid table');
db.query(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);

Common Pitfalls

  • Thinking ORMs make you immune — raw query escapes still happen and can be vulnerable
  • Escaping with custom logic instead of using the driver's parameter binding
  • Using LIKE patterns with user input — % and _ need escaping separately
  • Forgetting that error messages can leak schema info to attackers — sanitize errors in production

When NOT to Use This Skill

  • When the query has zero user input — there's nothing to inject
  • When you're using a fully managed query builder that already parameterizes everything

How to Verify It Worked

  • Try injection payloads: ' OR '1'='1, '; DROP TABLE users; --
  • Run the test against a copy of production schema
  • Check that prepared statements appear in your DB query logs

Production Considerations

  • Add a CI lint rule (e.g. semgrep) that fails the build on raw SQL with template literals
  • Use a Web Application Firewall as defense in depth
  • Audit DB user permissions — your app should not have DROP TABLE rights

Quick Info

CategorySQL
Difficultyintermediate
Version1.0.0
AuthorClaude Skills Hub
sqlsecurityinjection

Install command:

Want a SQL skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.