Une équipe de sécurité IA pour ton SaaS
Deux commandes Claude Code déploient huit sous-agents de sécurité : la phase 1 scanne ta logique SaaS pour détecter les failles RLS et les bugs d'auth, la phase 2 tente d'exploiter chaque résultat pour ne garder que les vrais bugs.
Arrêtez de configurer. Commencez à construire.
Templates SaaS avec orchestration IA.
Ton app a des failles de sécurité. Toutes les apps en ont. La question, c'est de savoir si tu les trouves avant tes utilisateurs.
Voilà à quoi ressemble une faille en pratique. Quelqu'un s'inscrit sur ton app. Il regarde autour. Il change un nombre dans la barre d'URL. Soudain, il voit les données privées d'un autre utilisateur. Infos de facturation, documents sauvegardés, messages personnels. Pas parce qu'il est un hacker. Juste parce que rien dans ton app ne l'en empêche.
C'est le type de bug que la plupart des SaaS livrent. Pas un hack façon film. Juste une règle manquante qui dit "tu ne peux voir que tes propres trucs."
Ce post décrit un système qui détecte ces bugs automatiquement. Deux commandes. Huit agents IA. La phase 1 trouve tout ce qui semble suspect. La phase 2 essaie vraiment d'entrer et prouve quels problèmes sont réels. Seuls les bugs confirmés font partie du rapport final.
Les cinq failles que la plupart des SaaS livrent
Ce sont les problèmes de sécurité les plus courants dans les apps construites par des solo founders, des indie hackers, et des vibe coders. Aucun ne nécessite de compétences en hacking pour être exploité. Un utilisateur curieux avec les outils développeur du navigateur peut en trouver la plupart.
1. Les utilisateurs peuvent voir les données des autres
Tu crées une table en base de données pour stocker les données utilisateurs. Profils, documents, paramètres, peu importe. Par défaut, la plupart des bases de données ne se soucient pas de qui demande les données. Si quelqu'un les demande, la base les livre.
La correction est une règle qui dit "ne retourne que les lignes appartenant à la personne qui demande." En termes de base de données, c'est la row-level security. Imagine un filtre qui ajoute automatiquement "WHERE user_id = la personne connectée" à chaque requête. Sans ça, n'importe quel utilisateur connecté peut demander les données de n'importe qui d'autre.
C'est la faille de sécurité la plus commune dans les SaaS. Un utilisateur change un ID dans l'URL ou ouvre les outils développeur, et il voit des choses qu'il ne devrait pas.
2. Quelqu'un contourne le login et frappe ton backend directement
Ton app a une page de login. Derrière, des endpoints API qui récupèrent et modifient les données. Le frontend envoie toujours le token de login avec chaque requête. Donc tu supposes que chaque requête a un token valide.
Mais quelqu'un peut appeler tes endpoints API directement, sans utiliser ton frontend. Avec des outils comme curl ou Postman. Si ton backend ne vérifie pas la présence d'un token de login valide sur chaque requête, c'est ouvert. Pas besoin de se connecter.
3. Des clés secrètes qui traînent dans le navigateur
Ton app parle à des services externes : processeurs de paiement, fournisseurs d'email, APIs IA. Chaque service te donne une clé secrète. Certaines de ces clés sont sûres à exposer dans le navigateur (comme ta clé Stripe publishable). D'autres ne le sont pas (comme ta clé secrète Stripe, ta clé API email, ou ta clé admin de base de données).
Si une clé secrète se retrouve dans ton code frontend, n'importe qui peut ouvrir les outils développeur, la trouver, et l'utiliser. Envoyer des emails depuis ton compte, débiter des cartes de crédit, ou accéder à ta base de données avec tous les droits admin.
4. Ton API dit aux gens plus qu'elle ne devrait
Ton endpoint de profil utilisateur retourne les données de l'utilisateur pour que le frontend les affiche. Mais le backend retourne tout ce qui est dans la ligne de la base de données, pas seulement ce dont le frontend a besoin. Email, nom complet, IDs internes, statut d'abonnement, peut-être même des hashes de mots de passe.
Un utilisateur appelle ton API et récupère ses propres données. Normal. Mais la réponse inclut 15 champs supplémentaires que le frontend n'utilise jamais. Maintenant il connaît ta structure interne. Pire, si la faille n°1 est aussi présente, il peut tirer cette information détaillée pour chaque utilisateur du système.
Les messages d'erreur en font partie aussi. Quand quelque chose rate, ton app peut retourner l'erreur brute de la base : "column 'stripe_customer_id' does not exist in table 'users'." Ça dit à un attaquant exactement comment ta base est structurée.
5. Des règles de sécurité navigateur manquantes
Les navigateurs ont des fonctionnalités de sécurité intégrées, mais elles ne fonctionnent que si ton app les active. Ce sont des headers HTTP que ton serveur envoie avec chaque réponse. Ils disent au navigateur des choses comme :
- "Ne laisse pas d'autres sites embarquer mon app dans un frame" (prévient le clickjacking)
- "N'exécute que des scripts que j'ai explicitement approuvés" (prévient l'injection de code)
- "N'accepte que des requêtes venant de mon propre domaine" (prévient les attaques cross-site)
Sans ces headers, ton app est exposée à des attaques que les navigateurs ont été conçus pour bloquer. La plupart des frameworks ne les activent pas par défaut.
Pourquoi les scanners de sécurité n'aident pas
Il existe des outils qui scannent ton code pour des problèmes de sécurité. Le problème : ils signalent tout ce qui semble mauvais, même quand c'est bien.
Un exemple. Ton app a un job en arrière-plan qui traite des paiements. Les jobs en arrière-plan n'ont pas d'utilisateur connecté, donc ils ont besoin d'un accès admin à la base pour fonctionner. Un scanner voit "accès admin base de données" et le signale comme vulnérabilité critique. Mais c'est correct. Le job a besoin de cet accès. Ce n'est pas un bug, c'est comme la feature fonctionne.
On appelle ça un faux positif. Le scanner a signalé quelque chose qui semble dangereux mais qui est en fait bien.
En pratique, ça arrive constamment. Le scanner rapporte 87 problèmes. Tu les lis tous. 82 sont des choses qui fonctionnent comme prévu. Les 5 vrais bugs sont enfouis dans une pile de fausses alarmes, et tu ne peux pas distinguer les uns des autres sans une connaissance approfondie de ta codebase.
Le problème central : les outils de sécurité ne comprennent pas ta logique métier. Ils ne savent pas que ton job en arrière-plan a besoin d'accès admin. Ils ne savent pas que ta table "ideas" est intentionnellement publique. Ils ne savent pas que ton flow d'onboarding utilise un pattern d'auth spécifique exprès. Ils voient juste des patterns qui semblent dangereux et les signalent.
La solution en deux phases
Le pipeline est deux commandes slash Claude Code. Chacune spawne une équipe d'agents IA qui travaillent en même temps.
.claude/
commands/
security.md # Phase 1: 5 agents scannent ton code
pentest.md # Phase 2: 3 agents tentent d'entrer
agents/
security-auditor.md # Règles que tous les agents Phase 1 suivent
dev/
reports/
security/ # Rapports Phase 1
pentest/ # Rapports Phase 2Phase 1 (Reporters) : Cinq agents lisent ton code et vérifient les cinq failles ci-dessus. Chaque agent se concentre sur une zone. Ils ont aussi accès à ta base de données live, pour vérifier ce qui est réellement déployé, pas juste ce que le code dit. Sortie : un rapport listant tout ce qui semble suspect.
Phase 2 (Exploiteurs) : Trois agents tentent vraiment d'entrer dans ton app en cours d'exécution. Ils lisent le rapport de Phase 1 et tentent d'exploiter chaque résultat. Ils envoient de vraies requêtes, essaient de vraies attaques, et enregistrent ce qui se passe. S'ils ne peuvent pas vraiment entrer, le résultat est marqué faux positif et supprimé. Sortie : un rapport validé où chaque résultat restant a une preuve attachée.
Le filtre entre les deux phases, c'est ce qui fait que ça marche. La Phase 1 attrape tout ce qui est suspect. La Phase 2 prouve ce qui est réel. Les fausses alarmes meurent en Phase 2 au lieu de te faire perdre du temps.
Phase 1 : cinq reporters
Chaque reporter est un agent IA qui se concentre sur un type de problème de sécurité. Ils tournent tous en même temps.
Auditeur d'accès base de données
Vérifie si les utilisateurs peuvent voir les données des autres. Se connecte à ta base live et regarde les règles d'accès réelles, pas juste le code. Trouve les tables où les données utilisateurs sont stockées mais sans règle "ne retourne que tes propres lignes". Vérifie aussi les fonctions de base de données qui ont plus de permissions qu'elles ne devraient.
Auditeur de validation des inputs
Vérifie chaque endroit où ton app accepte des inputs utilisateurs. Quelqu'un peut-il taper du code dans un champ de formulaire et le faire exécuter ? Peut-il envoyer une chaîne soigneusement construite qui trompe ta base pour exécuter des commandes ? Peut-il uploader un fichier avec un nom comme ../../etc/passwd et lire des fichiers qu'il ne devrait pas ? Cet agent teste tout ça.
Auditeur de login et sessions
Vérifie si ton système de login est solide. Y a-t-il des endpoints qui devraient nécessiter un login mais n'en demandent pas ? Quelqu'un peut-il appeler ton API avec un token de login faux ou expiré et quand même entrer ? Un utilisateur régulier peut-il accéder aux features admin en modifiant son token ? Y a-t-il quelque chose qui empêche quelqu'un d'essayer des milliers de mots de passe ?
Auditeur de fuite de données
Vérifie ce que ton app révèle. Les réponses API retournent-elles des champs supplémentaires que le frontend n'utilise pas ? Les messages d'erreur montrent-ils des détails internes de la base ? Y a-t-il des clés secrètes dans ton JavaScript frontend qui ne devraient pas y être ? Des données sensibles apparaissent-elles dans les URLs où l'historique du navigateur ou les logs serveur peuvent les capturer ?
Auditeur de configuration
Vérifie les paramètres de sécurité de ton app. Les headers de sécurité navigateur sont-ils activés ? Ton app dit-elle aux navigateurs d'accepter des requêtes depuis n'importe quel site (elle ne devrait pas) ? Tes cookies de login sont-ils correctement configurés ? Y a-t-il des vulnérabilités connues dans les packages dont ton app dépend ?
Les cinq tournent en même temps. Chacun renvoie ses résultats sous forme de texte. Aucun ne modifie ton code. Un orchestrateur lit tout et combine ça en un seul rapport.
La clé pour moins de fausses alarmes : la conscience de la logique métier
C'est ce qui sépare ces agents d'un scanner de sécurité ordinaire.
Chaque codebase a des choses qui semblent mauvaises mais sont correctes. Les agents doivent le savoir dès le départ. Sinon ils les signaleront à chaque fois, comme n'importe quel autre scanner.
La définition de l'agent inclut une section appelée "Documented Exceptions". C'est une liste de patterns que les agents doivent reconnaître et sauter. Des choses comme :
- Les jobs en arrière-plan qui ont besoin d'accès admin à la base (il n'y a pas d'utilisateur connecté, donc l'accès admin est le seul moyen)
- Les tables qui stockent des données publiques et sont intentionnellement lisibles par tout le monde
- Les patterns d'auth qui récupèrent des infos utilisateur supplémentaires lors de l'inscription (nécessaire pour des choses comme obtenir le nom d'un utilisateur depuis Google)
- Les clés API publiques censées être dans le navigateur (comme ta site key pour la protection contre les bots)
- Les tables gérées par des services tiers (ton fournisseur de paiement synchronise des données dans ses propres tables)
Chaque exception est spécifique : quand le pattern apparaît, pourquoi c'est correct. L'agent vérifie sa liste d'exceptions avant de générer un résultat. Si un pattern correspond, il le saute. Pas de fausse alarme.
Cette liste est la chose la plus efficace que tu puisses écrire. Commence avec 5 à 10 entrées. Après chaque audit, ajoute les faux positifs qui passent. Au troisième run, les agents éliminent plus de 90% du bruit avant qu'il t'atteigne.
Les agents peuvent aussi se connecter à ta base live et vérifier ce qui est réellement déployé. Le code dit ce qui devrait être vrai. Une requête live montre ce qui est vrai. Si un script de migration était censé ajouter des contrôles d'accès à une table mais a échoué silencieusement, la requête live le détecte. Ça élimine toute une catégorie de faux positifs : les choses où le code semble bon mais le déploiement ne correspond pas.
Scope : ne vérifier que ce qui a changé
Faire tourner cinq agents sur toute ta codebase à chaque fois est coûteux. La plupart du temps, tu n'as besoin de vérifier que ce qui a changé depuis le dernier rapport.
La commande gère ça automatiquement. Elle regarde la date du dernier rapport de sécurité, trouve tous les fichiers qui ont changé depuis, et envoie uniquement ces fichiers aux agents. Si rien de pertinent pour la sécurité n'a changé, elle sort tôt.
Les scans complets sont pour le premier audit ou après un gros refactoring. Tout le reste est scopé aux changements récents.
Phase 2 : trois exploiteurs
La Phase 2 lit le rapport de Phase 1 et essaie vraiment d'entrer dans ton app en cours d'exécution. Le serveur de dev doit tourner. Ces agents font de vraies requêtes et essaient de vraies attaques.
Exploiteur API
Appelle tes endpoints backend directement. Essaie les attaques de la faille n°1 (changer des IDs pour accéder aux données d'autres utilisateurs), la faille n°2 (appeler des endpoints sans token de login), et la faille n°3 (envoyer des caractères spéciaux qui pourraient tromper la base). Enregistre chaque requête et réponse comme preuve.
Exploiteur navigateur
Ouvre ton app dans un navigateur et essaie les attaques des failles n°4 et n°5. Tape du code dans des champs de formulaire pour voir s'il s'exécute. Vérifie si ton app peut être embarquée dans la page d'un autre site (ce qui pourrait tromper les utilisateurs en leur faisant cliquer sur des choses). Copie un token de login, déconnecte-toi, et essaie d'utiliser l'ancien token pour voir s'il fonctionne encore.
Exploiteur de login
Se concentre entièrement sur ton authentification. Se connecte en tant qu'utilisateur régulier et essaie d'accéder aux features admin. Essaie de modifier le token de login pour changer l'ID utilisateur ou le niveau de permission. Envoie 50 tentatives de login rapides pour voir s'il y a une limite de taux. Teste le flow de réinitialisation de mot de passe pour des façons de réutiliser des tokens.
Chaque résultat a besoin de preuve. La requête exacte qui a été envoyée et la réponse exacte qui est revenue. Si un agent ne peut pas produire la preuve que l'attaque a fonctionné, le résultat est tué. C'est pourquoi la Phase 2 élimine les faux positifs : l'agent doit vraiment exploiter le bug, pas juste dire qu'il pourrait exister.
Le filtre en action
Dans un vrai audit d'une app SaaS de production, les chiffres ressemblaient à ça :
| Étape | Nombre |
|---|---|
| Issues rapportées Phase 1 | 87 |
| Fausses alarmes tuées Phase 2 | 82 |
| Vrais bugs confirmés | 5 |
| Bruit éliminé | 94% |
Les 82 résultats tués étaient des choses comme : accès admin base de données dans un job en arrière-plan (correct), tables publiques sans règles d'accès par utilisateur (intentionnellement publiques), un pattern d'auth spécifique utilisé lors de l'inscription (nécessaire pour cette feature), messages d'erreur verbeux qui n'apparaissent qu'en mode développement (pas en production).
Les 5 bugs confirmés étaient réels. Un permettait à n'importe quel utilisateur de se donner l'accès admin en mettant à jour son profil. Un autre permettait à n'importe qui d'ajouter des crédits illimités à son propre compte. Un troisième était un open redirect dans le flow de paiement qui pouvait envoyer les utilisateurs vers un faux site après le checkout. Chacun venait avec le changement de code spécifique pour le corriger.
Sans la Phase 2, tu as 87 items et aucune idée desquels comptent. Avec la Phase 2, tu as 5 items prouvés réels, avec les preuves de l'attaque attachées.
Lancer le système
Deux commandes :
/securityPhase 1. Cinq agents scannent en même temps. Par défaut, les changements depuis le dernier rapport. Le rapport se sauvegarde dans dev/reports/security/. S'il trouve des problèmes sérieux, il te dit de lancer la Phase 2.
/pentestPhase 2. Lit le rapport de Phase 1. Démarre ton serveur de dev s'il ne tourne pas déjà. Trois agents tentent d'entrer en même temps. Le rapport validé se sauvegarde dans dev/reports/pentest/.
| Flag | Commande | Ce qu'il fait |
|---|---|---|
--full | /security | Scanne tout, pas juste les changements récents |
--days N | /security | Vérifie les changements des N derniers jours |
--skip-security | /pentest | Utilise le dernier rapport Phase 1 au lieu de le relancer |
--api-only | /pentest | Teste seulement le backend |
--browser-only | /pentest | Teste seulement le frontend |
--auth-only | /pentest | Teste seulement le système de login |
Règles pour construire ça toi-même
Le pattern fonctionne avec n'importe quelle base de données, n'importe quel framework, n'importe quel fournisseur d'auth. Voilà ce qui le fait marcher.
Écris ta liste d'exceptions avant le premier scan. Chaque app a des choses qui semblent mauvaises mais sont bien. Les agents ont besoin de cette liste dès le départ. Commence avec les patterns que tu sais être corrects. Ajoute les faux positifs de chaque run. La liste se stabilise après 2 ou 3 audits.
Donne aux agents accès à la vraie base, pas juste au code. Le code dit ce qui devrait être vrai. La base live montre ce qui est vrai. Si ces deux là ne correspondent pas, tu as un problème que le code ne peut pas te dire.
Sépare trouver de prouver. Les agents Phase 1 rapportent tout ce qui est suspect. Les agents Phase 2 essaient de l'exploiter. Mettre les deux jobs dans un seul agent crée un conflit. Il rapporte soit trop (bruyant) soit trop peu (rate des choses). Deux phases avec des jobs différents produisent de meilleurs résultats.
Exige des preuves, pas des opinions. Ne demande jamais à un agent "est-ce sécurisé ?" Demande-lui de montrer la requête et la réponse qui prouvent que l'attaque a fonctionné. La preuve force une vraie vérification. Les opinions invitent aux raccourcis.
Chaque résultat a besoin d'un fix. Pas "envisage d'améliorer ta sécurité." La ligne spécifique à changer et ce qu'il faut changer. Un résultat sans fix est un résultat qui restera dans un dossier pour toujours.
Inclus ce qui a fonctionné. Le rapport Phase 2 devrait lister les attaques qui ont échoué. Injection bloquée. Exécution de script bloquée. Requêtes cross-site bloquées. Savoir ce que ton app défend est aussi précieux que savoir ce qu'elle ne défend pas.
Au-delà de la sécurité
Le pattern en deux phases (trouver tout, puis prouver ce qui est réel) fonctionne pour plus que la sécurité.
Revue de code. Les agents Phase 1 signalent les problèmes potentiels. Les agents Phase 2 écrivent des tests qui échouent pour prouver que les problèmes sont réels. Faux positifs tués de la même façon.
Performance. Les agents Phase 1 identifient les requêtes de base de données lentes et les gros bundles de fichiers. Les agents Phase 2 lancent de vrais benchmarks. Une "requête lente" qui prend 2 millisecondes sur de vraies données n'est pas un vrai problème.
Conformité. Les agents Phase 1 signalent les patterns de traitement de données. Les agents Phase 2 tracent où les données circulent vraiment pour vérifier si les signalements comptent. Une fonction qui traite des analytics anonymes n'a pas besoin de gestion du consentement de confidentialité, même si le pattern ressemble à une qui en a besoin.
Même idée centrale à chaque fois. Donne aux agents assez de contexte pour comprendre pourquoi le code existe. Sépare trouver de prouver. Filtre le bruit avant qu'il t'atteigne.
Arrêtez de configurer. Commencez à construire.
Templates SaaS avec orchestration IA.
Quatre agents de distribution qui tournent tout seuls
Quatre agents Claude Code sur cron : l'un écrit des posts SEO depuis les tendances, l'autre lit PostHog, le troisième fabrique des carousels, et le dernier prospecte sur Reddit. Copie les définitions et branche-les.
Essaim IA autonome : comment construire un système qui livre des features pendant la nuit
Un essaim Claude Code autonome : un déclencheur toutes les 30 minutes, un orchestrateur, des agents spécialisés dans des worktrees isolés, et cinq portes qualité pour livrer des features en dormant.