{
  "id": "ai-writes-insecure-sql",
  "type": "failures",
  "category": "failures",
  "locale": "fr",
  "url": "/fr/failures/ai-writes-insecure-sql",
  "title": "Comment corriger les requêtes SQL non sécurisées écrites par l'IA",
  "description": "Les agents IA construisent des requêtes SQL avec interpolation de chaînes au lieu d'instructions paramétrées, introduisant des vulnérabilités d'injection SQL dans le code de base de données en production.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "PostgreSQL",
    "TypeScript"
  ],
  "tags": [
    "sql",
    "security",
    "postgres"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "L'agent utilise des template literals pour construire des requêtes SQL, créant des vecteurs d'injection SQL classiques qui semblent fonctionner correctement lors des tests mais sont exploitables en production.\n\n## Le symptôme\n\nLes valeurs contrôlées par l'utilisateur sont interpolées directement dans une chaîne SQL.\n\n```ts\n// WRONG — SQL injection vulnerability\nasync function getUserByEmail(email: string) {\n  const result = await db.query(\n    `SELECT * FROM users WHERE email = '${email}'`\n    //                                  ^^^^^^^ attacker-controlled\n  );\n  return result.rows[0];\n}\n\n// Attacker input: ' OR '1'='1\n// Resulting query: SELECT * FROM users WHERE email = '' OR '1'='1'\n// Returns every row in the table.\n```\n\n## Pourquoi cela se produit\n\nLes template literals sont l'outil de construction de chaînes le plus naturel en JavaScript, et de nombreux exemples de tutoriels sur lesquels le modèle a été entraîné les utilisent pour SQL sans paramétrage. L'agent ne modélise pas non plus les entrées adverses — il imagine des données bien formées passant à travers.\n\n## Comment le repérer\n\n- Les chaînes SQL qui contiennent des interpolations `${...}`.\n- Les fonctions de requête qui acceptent une entrée utilisateur et la passent à un helper de requête brute sans un tableau de paramètres séparé.\n- `db.query(sql)` appelé avec un seul argument au lieu de `db.query(sql, [params])`.\n- Les motifs `LIKE '%${term}%'`.\n\n## Comment le corriger\n\nUtilisez toujours des requêtes paramétrées. Le pilote de base de données gère l'échappement ; votre code ne touche jamais aux guillemets.\n\n```ts\n// CORRECT — parameterized query (node-postgres / pg)\nasync function getUserByEmail(email: string) {\n  const result = await db.query(\n    \"SELECT id, name, email FROM users WHERE email = $1\",\n    [email]  // second argument: params array\n  );\n  return result.rows[0] ?? null;\n}\n\n// CORRECT — with Postgres.js (template tag)\nasync function searchUsers(term: string) {\n  return sql`SELECT id, name FROM users WHERE name ILIKE ${\"%\" + term + \"%\"}`;\n  // postgres.js automatically parameterizes template expressions\n}\n```\n\n```txt\n[ ] No ${...} inside raw SQL strings — use $1/$2 placeholders instead\n[ ] Every db.query() call passes user input via the params array, not the SQL string\n[ ] Use an ORM (Prisma, Drizzle) or query builder for complex queries\n[ ] LIKE wildcards are appended in the param value, not concatenated into the SQL\n[ ] Run sqlfluff or a SQL linter in CI to catch interpolated strings\n```\n\n## Prompt de correction\n\n```txt title=\"Fix Prompt\"\nThis SQL query uses string interpolation with user-supplied values, which is a\nSQL injection vulnerability. Rewrite every raw query to use parameterized\nstatements ($1, $2 placeholders for pg, or the tagged template literal form for\npostgres.js). Never interpolate variables directly into SQL strings. If the\nquery is complex, migrate it to Prisma or Drizzle ORM instead.\n```\n\n## Test\n\n```bash\n# Detect template literal interpolation inside SQL-looking strings\ngrep -rn 'query(`\\|sql`\\|execute(`' --include=\"*.ts\" --include=\"*.tsx\" . \\\n  | grep '\\${' \\\n  | grep -v \"node_modules\" \\\n  && echo \"FAIL: interpolated SQL found\" || echo \"OK\"\n```"
}