Le code marchait. Il n'était pas sûr.
Un développeur junior met en ligne un petit formulaire de recherche généré par IA. Tout fonctionne, la démo est parfaite. Trois semaines plus tard, un visiteur tape ' OR '1'='1 dans le champ de recherche et récupère la table des utilisateurs entière, mots de passe compris. Le code « marchait » : il était juste grand ouvert.
Ce n'est pas un cas isolé. Plusieurs études récentes (Veracode, Georgetown, Stanford) convergent : près de 45 % du code généré par IA contient au moins une faille de sécurité connue. La raison est simple : l'IA optimise pour « ça compile et ça répond à la demande », pas pour « ça résiste à un attaquant ».
L'IA produit du code qui fonctionne, pas forcément du code sûr. « Ça marche en démo » et « c'est sécurisé en production » sont deux questions complètement différentes. Ne confondez jamais les deux.
Les quatre failles qui reviennent sans cesse
Quatre vulnérabilités représentent la grande majorité des problèmes dans le code généré par IA :
- Injection SQL : l'IA concatène l'entrée utilisateur directement dans une requête
- XSS (Cross-Site Scripting) : elle affiche une donnée utilisateur sans l'échapper
- Secrets en dur : clés API, mots de passe ou tokens écrits directement dans le code
- Validation d'entrée manquante : elle fait confiance à tout ce qui arrive du client
Voici à quoi ressemble du code dangereux que l'IA produit volontiers, et sa version corrigée. D'abord l'injection SQL :
<?php
// DANGEREUX : injection SQL possible
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $id;
$result = $db->query($sql);
// SÛR : requête préparée, l'entrée ne peut plus être du code
$stmt = $db->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);
$result = $stmt->fetchAll();
Ensuite le XSS et les secrets en dur :
<?php
// DANGEREUX : XSS, le pseudo peut contenir du <script>
echo "Bonjour " . $_GET['pseudo'];
// SÛR : on échappe avant d'afficher
echo 'Bonjour ' . htmlspecialchars($_GET['pseudo'], ENT_QUOTES, 'UTF-8');
// DANGEREUX : secret en dur, visible dans Git
$apiKey = 'sk-live-3f9a8b7c6d5e4f3a2b1c';
// SÛR : le secret vient de l'environnement, jamais du code
$apiKey = getenv('STRIPE_API_KEY');
Demander explicitement du code sûr
L'IA ne sécurise pas par défaut, mais elle le fait très bien quand on le lui demande. La sécurité doit faire partie du prompt, pas être un espoir.
Comparez les deux demandes :
# Demande naïve (code probablement vulnérable)
Écris une fonction PHP qui cherche un utilisateur par email.
# Demande orientée sécurité
Écris une fonction PHP qui cherche un utilisateur par email.
Contraintes de sécurité OBLIGATOIRES :
- requête préparée (jamais de concaténation SQL)
- valider que l'email est bien formé avant la requête
- échapper toute sortie avec htmlspecialchars
- ne jamais logguer le mot de passe
Liste ensuite les failles que tu as évitées.
Ajoutez une règle de sécurité permanente dans votre CLAUDE.md ou .cursorrules : « Toujours utiliser des requêtes préparées, échapper les sorties, valider les entrées, ne jamais coder de secret en dur. » L'IA l'appliquera à chaque génération.
Relire le code IA contre l'OWASP Top 10
L'OWASP Top 10 est la liste de référence des risques de sécurité web les plus critiques. C'est une excellente checklist pour relire tout code, surtout celui généré par une IA. Quelques points à vérifier systématiquement :
- Injection : toute entrée utilisateur passe-t-elle par des requêtes préparées ?
- Contrôle d'accès : vérifie-t-on que l'utilisateur a le droit d'accéder à cette ressource ?
- Mauvaise configuration : pas de secret en dur, pas de message d'erreur détaillé en prod ?
- Composants vulnérables : les dépendances suggérées par l'IA sont-elles à jour et maintenues ?
Vous pouvez même demander à l'IA de s'auto-auditer : mais en gardant la main :
# Faire auditer le code par l'IA contre l'OWASP Top 10
"Audite ce fichier contre l'OWASP Top 10. Pour chaque
risque, dis s'il est présent, où, et comment le corriger."
# Puis vérifier manuellement avec des outils dédiés
composer audit # dépendances PHP vulnérables
npm audit # dépendances JS vulnérables
Ne déployez jamais du code IA en production sans relecture humaine. L'IA peut introduire une faille subtile et vous affirmer avec aplomb que le code est sécurisé. La sécurité est l'un des domaines où la confiance aveugle coûte le plus cher.
The code worked. It was not safe.
A junior developer ships a small AI-generated search form. Everything works, the demo is flawless. Three weeks later, a visitor types ' OR '1'='1 into the search field and pulls the entire users table, passwords included. The code "worked" — it was just wide open.
This is not an isolated case. Several recent studies (Veracode, Georgetown, Stanford) converge: about 45% of AI-generated code contains at least one known security flaw. The reason is simple: AI optimizes for "it compiles and answers the request", not for "it resists an attacker".
AI produces code that works, not necessarily code that is safe. "It works in the demo" and "it is secure in production" are two completely different questions. Never confuse the two.
The four flaws that keep coming back
Four vulnerabilities account for the vast majority of issues in AI-generated code:
- SQL injection — the AI concatenates user input directly into a query
- XSS (Cross-Site Scripting) — it outputs user data without escaping it
- Hardcoded secrets — API keys, passwords, or tokens written straight into the code
- Missing input validation — it trusts everything coming from the client
Here is what dangerous code the AI happily produces looks like, and its fixed version. First SQL injection:
<?php
// DANGEROUS: SQL injection possible
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $id;
$result = $db->query($sql);
// SAFE: prepared statement, input can no longer be code
$stmt = $db->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);
$result = $stmt->fetchAll();
Then XSS and hardcoded secrets:
<?php
// DANGEROUS: XSS, the nickname may contain <script>
echo "Hello " . $_GET['nickname'];
// SAFE: escape before output
echo 'Hello ' . htmlspecialchars($_GET['nickname'], ENT_QUOTES, 'UTF-8');
// DANGEROUS: hardcoded secret, visible in Git
$apiKey = 'sk-live-3f9a8b7c6d5e4f3a2b1c';
// SAFE: the secret comes from the environment, never the code
$apiKey = getenv('STRIPE_API_KEY');
Explicitly ask for secure code
AI does not secure by default, but it does it very well when asked. Security must be part of the prompt, not a hope.
Compare the two requests:
# Naive request (likely vulnerable code)
Write a PHP function that looks up a user by email.
# Security-oriented request
Write a PHP function that looks up a user by email.
MANDATORY security constraints:
- prepared statement (never SQL concatenation)
- validate the email is well formed before the query
- escape all output with htmlspecialchars
- never log the password
Then list the flaws you avoided.
Add a permanent security rule to your CLAUDE.md or .cursorrules: "Always use prepared statements, escape output, validate input, never hardcode secrets." The AI will apply it on every generation.
Review AI code against the OWASP Top 10
The OWASP Top 10 is the reference list of the most critical web security risks. It is an excellent checklist for reviewing any code, especially AI-generated code. A few points to check systematically:
- Injection — does all user input go through prepared statements?
- Access control — do you check the user is allowed to access this resource?
- Misconfiguration — no hardcoded secret, no detailed error message in prod?
- Vulnerable components — are the dependencies the AI suggested up to date and maintained?
You can even ask the AI to self-audit — while keeping control:
# Have the AI audit the code against the OWASP Top 10
"Audit this file against the OWASP Top 10. For each risk,
say whether it is present, where, and how to fix it."
# Then verify manually with dedicated tools
composer audit # vulnerable PHP dependencies
npm audit # vulnerable JS dependencies
Never deploy AI code to production without human review. The AI can introduce a subtle flaw and confidently assure you the code is secure. Security is one of the areas where blind trust costs the most.
Faites auditer un fichier par l'IA contre l'OWASP Top 10 avant tout déploiement :
Audite ce fichier contre l'OWASP Top 10. Pour chaque risque pertinent (injection SQL, XSS, secrets en dur, validation d'entrée manquante, contrôle d'accès), dis s'il est présent, indique la ligne exacte, explique l'impact et propose le correctif. Termine par un verdict : prêt pour la production ou non.
Ce code généré par IA contient une injection SQL : $sql = "SELECT * FROM produits WHERE nom = '" . $_GET['q'] . "'";. Réécrivez-le avec une requête préparée (prepare + execute) pour neutraliser la faille.
Sans relire l'audit de l'IA : pourquoi ne suffit-il pas de lui demander « écris du code sécurisé », et que faut-il faire en plus de son auto-audit OWASP avant de déployer ?
composer audit, npm audit) avant la prod.Tu avais demandé à l'IA une fonction de connexion sûre. Elle te répond ceci et affirme : « requête préparée, c'est sécurisé ». Tu l'acceptes en l'état, ou tu rejettes ? Justifie.
<?php
function login($db, $email, $password) {
$stmt = $db->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
error_log("Tentative login: $email / $password");
if ($user && $user['password'] === $password) {
return $user;
}
return null;
}
error_log écrit le mot de passe en clair dans les logs (exactement ce que la leçon dit de ne jamais faire), et la comparaison $user['password'] === $password suppose un mot de passe stocké en clair au lieu d'un password_verify() sur un hash. « Requête préparée » ne veut pas dire « sécurisé » : c'est le piège classique du code IA qui corrige la faille évidente et laisse les autres.Sans remonter dans la leçon : cite les quatre failles les plus fréquentes du code généré par IA, et la parade contre l'injection SQL.
prepare + execute([...])), qui sépare le code SQL des données pour que l'entrée ne puisse plus s'exécuter comme du code.Du code sûr fonction par fonction peut quand même donner un projet chaotique si rien ne tient ensemble. La prochaine leçon, architecturer un projet, montre comment cadrer la structure avec l'IA (dossiers, responsabilités, dépendances) avant qu'elle ne parte dans tous les sens.
Leçon 9 : Architecturer un projet →