LLMs et sécurité du code : ce qu'il faut savoir

Par KamangaFeb 13, 20268 mins de lecture

En construisant crmcoaching (mon SaaS pour coachs professionnels), je développe seul avec Claude Code comme assistant principal. Un jour, Claude a généré un service NestJS pour récupérer les clients d'un coach. Le code compilait, les tests Vitest passaient, le type Prisma était correct. Sauf que la requête était construite par concaténation de chaîne via $queryRawUnsafe, et que la clé Stripe utilisée pour initialiser le SDK était écrite en dur dans le fichier de service, en clair, versionnée dans Git.

Ce n'était pas de la malveillance de la part de Claude. C'était la reproduction statistique des patterns présents dans son corpus d'entraînement.

Un LLM génère du code injectable et du code parfaitement sécurisé avec la même confiance syntaxique. Il ne distingue pas les deux. Votre processus de review doit le faire, et en 2026, la plupart des développeurs solos ou en petite équipe n'ont pas adapté leur review au code IA-assisté.

Deux études publiées en 2023 ont documenté le problème. Stanford University : 40 % du code suggéré dans des contextes de sécurité spécifiques contient des vulnérabilités. NYU : les développeurs qui utilisent des assistants IA tendent à produire du code moins sécurisé que sans assistant, parce qu'ils font plus confiance au code généré et le reviewent moins rigoureusement. Ce chiffre est contre-intuitif mais cohérent avec ce que j'observe au quotidien sur crmcoaching.


Pourquoi les LLMs génèrent du code vulnérable

L'explication est simple mais souvent ignorée : les LLMs sont entraînés sur du code public. Le code public contient des vulnérabilités courantes. Les LLMs reproduisent les patterns du code sur lequel ils ont été entraînés.

Le résultat : les patterns vulnérables les plus fréquents dans le code public (injections, secrets hardcodés, dépendances non vérifiées) sont aussi les plus fréquemment générés par les LLMs. Pas par malveillance. Par statistique.


Vulnérabilité type 1 : Injections (SQL, prompt, command)

Les LLMs génèrent facilement du code vulnérable aux injections, surtout quand le prompt ne spécifie pas explicitement l'usage de requêtes paramétrées.

Sur crmcoaching, Claude a généré ce service pour filtrer des clients par nom :

// ❌ Code généré par Claude sans précision sur la sécurité
// apps/api/src/infrastructure/prisma/client.repository.ts
async findByName(name: string): Promise<Client[]> {
  // $queryRawUnsafe concatène directement l'input utilisateur : SQL injection
  return this.prisma.$queryRawUnsafe(
    `SELECT * FROM "Client" WHERE name = '${name}'`
  );
}

// ✅ Code correct : requête paramétrée via $queryRaw (tagged template)
async findByName(name: string): Promise<Client[]> {
  return this.prisma.$queryRaw<Client[]>`
    SELECT * FROM "Client" WHERE name = ${name}
  `;
}

// ✅ Mieux encore : utiliser l'ORM Prisma directement
async findByName(name: string): Promise<Client[]> {
  return this.prisma.client.findMany({
    where: { name },
  });
}

La prompt injection est spécifique au code qui intègre des LLMs dans des applications : si votre application passe de l'input utilisateur directement dans un prompt, un attaquant peut modifier le comportement du modèle via des instructions injectées. C'est une vulnérabilité nouvelle, documentée par l'OWASP Top 10 for LLM Applications depuis 2023.

Garde-fou : lors de la review de tout code qui touche à la gestion des inputs utilisateurs, vérifier systématiquement que les requêtes sont paramétrées et que les inputs ne sont pas interpolés directement dans des strings.


Vulnérabilité type 2 : Gestion des secrets et credentials

C'est le pattern de vulnérabilité le plus fréquemment généré par les LLMs : credentials hardcodées, tokens dans les logs, secrets dans les fichiers de configuration versionnés.

Sur crmcoaching, voici exactement ce que Claude a généré lors de l'initialisation du service Stripe :

// ❌ Pattern généré par Claude : clé Stripe hardcodée dans le service NestJS
// apps/api/src/infrastructure/stripe/stripe.service.ts
@Injectable()
export class StripeService {
  private stripe = new Stripe("sk_live_XXXXXXXXXXXXXXXXXXXXXXXX"); // ❌ hardcodé

  async createCheckoutSession(priceId: string) { /* ... */ }
}

// ❌ Pattern de logging qui expose un secret Brevo
@Injectable()
export class EmailService {
  sendWelcome(email: string) {
    this.logger.log(`Sending via Brevo key: ${process.env.BREVO_API_KEY}`); // ❌
  }
}

// ✅ Pattern correct : injection de config NestJS via variables d'environnement
@Injectable()
export class StripeService {
  private stripe: Stripe;

  constructor(private readonly configService: ConfigService) {
    this.stripe = new Stripe(
      this.configService.getOrThrow<string>("STRIPE_SECRET_KEY")
    );
  }

  async createCheckoutSession(priceId: string) { /* ... */ }
}

La raison : les LLMs ont été entraînés sur du code d'exemple qui contient fréquemment des credentials "de test" hardcodées. Ils reproduisent ce pattern naturellement.

Garde-fou : outil SAST (Semgrep, GitHub Secret Scanning, Gitleaks) dans la CI qui détecte les patterns de credentials hardcodées avant le merge. Ce check doit être bloquant.

Vous voulez repérer une injection ou un secret hardcodé dans une PR Claude avant qu'il atteigne la prod ?

Distinguer un $queryRaw paramétré d'une concaténation dangereuse, ça ne s'apprend pas en lisant un article : ça se travaille sur du vrai code. En mentoring 1:1, je relis vos PR IA-assistées avec vous, on construit votre checklist de review personnelle et vous développez le réflexe qui attrape ces vulnérabilités avant le merge. Du 1:1 pour monter en niveau, pas un audit d'équipe.


Vulnérabilité type 3 : Dépendances obsolètes ou hallucinations

Quand un LLM génère du code qui importe des librairies externes, deux risques spécifiques apparaissent :

Dépendances avec CVE connus : Claude suggère une version d'une librairie qui avait des vulnérabilités connues au moment de son entraînement, et qui ont pu être corrigées depuis, mais la version vulnérable reste dans le code généré.

Package hallucination : les LLMs peuvent inventer des noms de packages plausibles qui n'existent pas (ou qui existent sous un nom de typosquat malveillant). C'est le vecteur de l'attaque "dependency confusion", documentée par de nombreux chercheurs en sécurité depuis 2021.

# Claude suggère d'importer "nestjs-prisma-query-helper" : package qui n'existe pas
# Un attaquant peut publier ce package sur npm/pnpm avec du code malveillant
pnpm add nestjs-prisma-query-helper  # ❌ vérifier l'existence avant d'installer

Garde-fou : ne jamais installer un package suggéré par Claude sans vérifier son existence sur le registre officiel et son score de sécurité (pnpm audit, Snyk, Socket.dev).


Les 5 garde-fous à mettre en place

Garde-fou 1 : SAST dans la CI

SonarQube, Semgrep, ou GitHub Advanced Security détectent les patterns de vulnérabilités courants indépendamment de l'origine du code, qu'il soit humain ou IA. Ce check doit être bloquant sur les vulnérabilités Critical et High.

Garde-fou 2 : Checklist de review spécifique au code IA

Au-delà de la review standard, je vérifie explicitement pour tout code généré par Claude (voir la checklist complète en 12 points) :

  • Aucune credential hardcodée
  • Toutes les requêtes DB utilisent l'ORM Prisma ou des templates paramétrés ($queryRaw)
  • Les dépendances importées ont été vérifiées sur le registre officiel
  • Les inputs utilisateurs sont validés par un schéma Zod avant tout traitement

Garde-fou 3 : Politique de prompt

Documenter quelles données peuvent et ne peuvent pas être incluses dans les prompts envoyés à des services IA : pas de données personnelles, pas de données clients, pas de credentials, pas de secrets d'infrastructure.

Garde-fou 4 : Former sa mémoire aux patterns dangereux

Une heure à relire du code vulnérable généré par IA suffit à développer des réflexes de détection durables. En solo, le plus efficace est de prendre ses propres findings passés (comme ceux décrits ici) et d'en faire une liste de vérification personnelle. Découvrez comment intégrer l'IA dans votre code review tout en renforçant la sécurité.

Garde-fou 5 : Audit trimestriel du code IA-assisté

Auditer trimestriellement un échantillon du code développé avec assistance IA pour identifier des patterns systémiques de vulnérabilité. C'est une pratique préventive, pas réactive.

Sur crmcoaching, l'introduction de GitHub Secret Scanning et d'une checklist de review dédiée au code Claude m'a permis de détecter, en quelques mois, plusieurs instances de secrets hardcodés et de requêtes construites par concaténation qui auraient atteint la production. Ces mesures ne prennent pas longtemps à mettre en place et couvrent l'essentiel des risques introduits par l'assistance IA.

L'IA accélère la production. Elle ne remplace pas le jugement de sécurité.

Ces 5 garde-fous ne sont qu'un début : il en existe 100

Relire une PR pour traquer une injection ou un secret hardcodé fait partie d'un ensemble bien plus large : le Craft Bundle réunit les 100 pratiques craft que j'applique pour coder propre, de la review de sécurité au design de code testable. Ce sont les réflexes qu'un LLM ne vous apprendra jamais, parce qu'il ne les a jamais vus tenir en production.


FAQ sur la sécurité du code LLM

1. Les LLMs vont-ils s'améliorer sur la sécurité du code au fil du temps ?

Oui, progressivement. Les LLMs récents sont significativement meilleurs que leurs prédécesseurs sur les patterns de sécurité de base. Mais ils continuent à faire des erreurs sur les vulnérabilités contextuelles, celles qui dépendent de la logique métier spécifique de votre application. Ces erreurs-là ne pourront pas être éliminées par l'amélioration des modèles seule.

2. Les outils SAST détectent-ils les vulnérabilités spécifiques au code IA-généré ?

Les SAST détectent les patterns de vulnérabilités connus indépendamment de l'origine du code. Ils sont efficaces sur les injections, les hardcoded secrets, et les dépendances vulnérables. Ils ne détectent pas les vulnérabilités logiques, c'est-à-dire le code qui fait quelque chose de sécuritairement incorrect mais syntaxiquement valide. Pour celles-là, la review humaine reste indispensable.

3. Faut-il une politique de sécurité spécifique pour le code généré par Claude ?

La politique doit être basée sur les données traitées et les clauses contractuelles, pas sur l'outil en lui-même. Questions à évaluer : les prompts sont-ils utilisés pour l'entraînement ? Anthropic propose-t-il un DPA compatible RGPD ? Les données sont-elles hébergées là où votre conformité l'exige ? Les réponses varient selon l'offre : Claude grand public, Claude Team ou Enterprise, ou l'API Anthropic.

4. Comment développer rapidement des réflexes face aux vulnérabilités du code LLM-généré ?

La méthode la plus efficace : relire des exemples réels de code vulnérable généré par IA et identifier les problèmes. Cette approche en "capture the flag" crée une mémoire musculaire plus durable que de la théorie. En solo, constituer une liste personnelle à partir de ses propres findings passés est encore plus ancré. Une heure sur dix exemples réels suffit à développer les réflexes de base.

5. Un développeur solo sans RSSI dédié peut-il gérer ces risques seul ?

Oui, avec 3 garde-fous prioritaires : GitHub Secret Scanning (activé gratuitement sur les repos GitHub, détecte les credentials avant le push), une règle de review PR personnelle qui checke les injections et les hardcoded secrets, et une politique simple : "aucune donnée client ou credential dans les prompts". Ces trois mesures couvrent 80 % des risques avec 20 % de l'effort.


Ressource gratuite : AI-Ready Engineering Team Checklist

La checklist AI-Ready inclut une section dédiée à la sécurité du code IA-assisté : critères de gouvernance, checklist de review spécifique, et politiques d'usage recommandées. Adaptable à votre contexte réglementaire.


Ecris par Kamanga

Expert IT avec 25 ans d'expérience en développement logiciel, diplômé EPITECH et MBA. Spécialisé en software craftsmanship, gestion du changement, stratégie, direction des systèmes d'information, coaching et certifié en agilité.