
Crochet de sécurité pré-écriture agnostique à l'hôte pour agent de codage : détecte les motifs de saisie utilisateur via Semgrep et émet des conseils de sécurité déterministes, sans LLM.
Un point de contrôle de sécurité pour les outils d'IA de codage. Il examine chaque fichier qu'un assistant IA écrit, et bloque les dangereux avant qu'ils n'atteignent le disque.
Les assistants de codage IA (Claude Code, Codex, …) écrivent du code rapidement — y compris du code qui manipule des mots de passe, des e-mails, des clés API ou des entrées utilisateur brutes. Il est facile pour un assistant de connecter ces données directement dans une requête de base de données, une commande shell ou une réponse HTTP sans penser à la sécurité.
VibeGate se place entre l'assistant et votre système de fichiers. Chaque fois que l'assistant essaie d'écrire ou de modifier un fichier, VibeGate scanne d'abord le nouveau code :
Aucun LLM n'est impliqué dans l'analyse elle-même — c'est une analyse statique rapide et déterministe, donc elle n'invente jamais rien et ne vous coûte jamais de tokens.
Voici tout ce que VibeGate vérifie actuellement :
La liste complète et actuelle se trouve dans guidance.TECHNICAL_RISKS et
formatter.BLOCKING_CATEGORIES, au cas où ce tableau deviendrait obsolète.
┌───────────────────────────────┐
│ Vous demandez à Claude Code │
│ d'écrire ou de modifier un fichier │
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ Claude Code essaie de sauvegarder │
│ le fichier (outil Write/Edit) │
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ Hook VibeGate │
│ (s'exécute automatiquement, │
│ avant que le fichier soit sauvegardé) │
└───────────────┬───────────────┘
│
scanne le nouveau code avec Semgrep
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────────┐ ┌────────────────────┐ ┌──────────────────────┐
│ Aucune entrée │ │ Entrée risquée, │ │ Entrée risquée │
│ risquée trouvée │ │ mais risque plus │ │ atteint un sink │
│ │ │ faible (ex. │ │ critique │
│ │ │ affichée dans une │ │ (SQL/commande/RCE, │
│ │ │ réponse HTTP) │ │ injection de │
│ │ │ │ │ template) │
└─────────┬──────────┘ └─────────┬──────────┘ └───────────┬──────────┘
│ │ │
▼ ▼ ▼
Le fichier est sauvegardé, Le fichier est sauvegardé, Le fichier N'EST PAS
rien n'est affiché. plus un avertissement sauvegardé.
dans le terminal avec Claude Code voit
le risque et comment la raison du blocage
le corriger. et reçoit les
instructions pour
corriger.
En résumé : le code sûr passe sans modification, le code risqué mais viable est sauvegardé avec un avertissement, et le code à un pas de l'injection SQL, de l'injection de commande ou de l'exécution de code à distance est bloqué avant d'atteindre le disque.
Si VibeGate lui-même rencontre une erreur inattendue, il laisse toujours l'écriture passer — un bug dans le hook ne doit jamais être la raison pour laquelle votre travail est bloqué.
Chaque avertissement et blocage comporte également une instruction explicite demandant à Claude Code de mentionner la découverte dans sa réponse, et non de la corriger silencieusement. C'est ce qui rend l'activité de VibeGate visible dans la conversation, pas seulement dans un journal de terminal que vous devriez aller chercher.
| Ce que VibeGate voit | Ce qui se passe |
|---|---|
| Aucune entrée utilisateur, ou un langage qu'il ne supporte pas encore | Le fichier est sauvegardé normalement, rien n'est affiché |
| Entrée utilisateur trouvée, mais le risque est modéré (ex. redirection ouverte, affectation massive) |
Voir le tableau dans "Quel problème cela résout-il ?" ci-dessus pour la répartition complète, vérification par vérification, de ce qui bloque par rapport à ce qui avertit seulement.
Aujourd'hui, VibeGate comprend Python, JavaScript/TypeScript, Go, Java, PHP et Ruby, et se branche sur Claude Code et Codex. D'autres langages et outils peuvent être ajoutés sans toucher à la logique centrale.
Il vérifie également les fichiers de workflow GitHub Actions pour deux erreurs
courantes de la chaîne d'approvisionnement CI/CD : les actions épinglées à un
tag mutable (@v4) au lieu d'un SHA de commit, et le déclencheur dangereux
pull_request_target. Les deux avertissent plutôt que bloquer, car ce sont
des vérifications de durcissement plutôt que la preuve d'une exploitation active.
Voici un enregistrement réel de Claude Code construisant une application de lecteur de flux RSS à partir de zéro, avec VibeGate en fonctionnement pendant tout le temps. Observez les moments où Claude Code s'arrête et explique explicitement ce que VibeGate a signalé, et pourquoi, avant de continuer — y compris un vrai risque SSRF dans le code de récupération de flux qu'il corrige sur-le-champ.
Voici un second exemple, sous forme d'image fixe : Claude Code construit une application qui permet de télécharger une photo et d'en voir les détails. VibeGate remarque que le nom du fichier et d'autres détails du fichier seront ensuite affichés à l'écran, et avertit que cela pourrait être utilisé pour injecter du code nuisible dans la page (c'est ce qu'on appelle XSS). Claude Code ajuste le code pour que les informations soient affichées en toute sécurité.
Dans les deux cas, rien n'a été bloqué sans raison, et personne n'a eu à lire le code ligne par ligne pour détecter le problème. VibeGate l'a détecté au moment où le fichier a été écrit, et l'IA l'a corrigé sur-le-champ.
Il existe deux façons de faire écrire du code plus sûr par un assistant IA. La première consiste à charger un grand ensemble d'instructions sur le codage sécurisé dans la conversation avant de commencer, par exemple une liste de vérification couvrant l'injection SQL, XSS, la gestion des mots de passe, les téléchargements de fichiers, etc. L'autre façon est ce que fait VibeGate : vérifier le code automatiquement, au moment où un fichier est écrit, et ne parler que lorsque quelque chose ne va pas.
La première approche coûte des tokens à chaque message, qu'ils soient nécessaires ou non. Une liste de vérification typique de codage sécurisé couvrant plusieurs catégories de risques peut facilement ajouter quelques milliers de tokens. Si un assistant IA écrit 50 fichiers en une session, et que cette liste est rechargée ou maintenue en contexte à chaque fois, vous pourriez payer pour bien plus de cent mille tokens de conseils qui, la plupart du temps, ne s'appliquent pas au fichier en cours d'écriture. Une page de connexion et un simple fichier de constante de couleur n'ont pas besoin des mêmes avertissements, mais une liste de vérification chargée ne peut pas les distinguer à l'avance.
VibeGate inverse cette logique. Il reste silencieux et ne coûte rien de supplémentaire pour chaque fichier qui ne contient aucun motif risqué. Seulement lorsqu'il trouve quelque chose, comme une entrée utilisateur qui circule vers une requête de base de données, il ajoute une note courte et spécifique sur ce seul problème, généralement une petite fraction de la taille d'une liste de vérification complète. Ainsi, au lieu de payer un coût fixe en tokens sur chaque fichier quoi qu'il arrive, vous payez un petit coût uniquement sur les fichiers qui nécessitent réellement une attention, et ce coût est exactement ciblé sur le problème trouvé, et non une conférence générale sur la sécurité.
Cela rend également les conseils plus fiables. Un assistant IA invité à "garder la sécurité à l'esprit" tout en écrivant une centaine de lignes de code peut tout simplement manquer une ligne risquée parmi tant d'autres. Une porte ne se fatigue pas et ne se laisse pas distraire : elle vérifie chaque écriture, à chaque fois, en utilisant les mêmes règles fixes.
Installez-le une fois — cela installe également Semgrep, dont VibeGate dépend :
pipx install git+https://github.com/theMiddleBlue/vibegate
Activez-le ensuite dans le projet que vous souhaitez protéger :
cd votre-projet
vibegate on # activez ici (rechargez Claude Code ensuite)
vibegate status # vérifiez s'il est actif pour ce projet
vibegate off # désactivez ici
vibegate on ajoute un hook PreToolUse pour Write|Edit|MultiEdit dans le fichier
.claude/settings.local.json de ce projet. Il est limité à chaque projet, donc
l'activer dans un dépôt n'affecte pas les autres.
Claude Code exécute le hook sous la forme vibegate run --host claude_code — aucun
chemin absolu n'est impliqué, donc il continue de fonctionner même si vous
réinstallez ou déplacez des éléments.
vibegate status affiche également un journal en cours des éléments que VibeGate a
effectivement détectés dans ce projet — chaque avertissement et blocage, avec le
fichier, la ligne et la catégorie — vous pouvez donc voir son activité au fil du
temps, pas seulement s'il est activé ou non :
$ vibegate status
█ █ █████ ████ █████ ████ ███ █████ █████
...
● VibeGate est ACTIVÉ dans .claude/settings.local.json
Activité récente (2 dernières sur 2 enregistrées, les plus récentes en premier) :
2026-07-02T17:35:48+00:00 ⛔ BLOQUÉ server.py:3 EXEC_INPUT (FREE_TEXT)
2026-07-02T17:35:46+00:00 ⚠ AVERTI app.py:2 HTTP_BODY (EMAIL)
Ce journal se trouve dans .vibegate/activity.jsonl à la racine du projet —
ajoutez-le à votre .gitignore, c'est un état local du développeur, pas quelque
chose à commiter.
VibeGate détermine à quel hôte il parle dans cet ordre : un drapeau explicite
--host <name>, puis la variable d'environnement VIBEGATE_HOST, puis une
détection automatique à partir de la charge utile entrante, en retombant sur
claude_code.
Si VibeGate signale quelque chose que vous avez délibérément jugé sûr, ajoutez un
commentaire vibegate-ignore sur la même ligne — cela fonctionne avec n'importe
quelle syntaxe de commentaire (#, //, …), car VibeGate cherche simplement le
texte :
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore
Pour supprimer uniquement des catégories spécifiques au lieu de tout sur cette ligne, listez-les après un deux-points (correspond soit à la catégorie technique, soit au type sémantique, séparés par des virgules, insensibles à la casse) :
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore: DB_QUERY
src/vibegate/
├── hook.py # point d'entrée
├── cli.py # commandes on/off/status + la bannière ASCII
├── activity_log.py # persiste les avertissements/blocages dans .vibegate/activity.jsonl
├── colors.py # codes de couleur ANSI partagés (rapport + bannière CLI)
├── core.py # le pipeline indépendant de l'hôte
├── models.py # InputEvent / ClassifiedFinding / AnalysisResult
├── semgrep_runner.py # exécute Semgrep en tant que sous-processus (sécurisé)
├── classifier.py # mappe la règle Semgrep → catégorie, nom de variable → type de données
├── guidance.py # les descriptions statiques des risques / corrections
├── formatter.py # transforme les résultats en rapport terminal + contexte hôte
├── adapters/ # base, claude_code, codex + un petit registre
└── rules/ # règles Semgrep — un fichier par langue (Python, JS/TS,
# Go, Java, PHP, Ruby) plus un espace réservé générique
Le pipeline lui-même (core.py) ne parle jamais directement à un hôte spécifique —
toutes les entrées/sorties spécifiques à l'hôte se trouvent dans adapters/, donc
l'ajout d'un nouvel hôte ne nécessite pas de toucher à la logique d'analyse.
semgrep --validate --config src/vibegate/rules/ # vérifie que les règles sont valides
pytest tests/ # tests unitaires + d'intégration
Pour le voir fonctionner de bout en bout sans Claude Code :
python3 -c 'import json; print(json.dumps({"tool_name":"Write","tool_input":{"file_path":"/tmp/t.py","new_content":"email = request.json.get(\"email\")"}}))' \
| python3 src/vibegate/hook.py --host claude_code
rules/<lang>-user-input.yaml, enregistrez les
nouveaux IDs de règles dans classifier.RULE_TO_TECHNICAL, et mappez l'extension
de fichier dans core.EXT_TO_LANGUAGE.classifier.VARNAME_TO_SEMANTIC et une description dans guidance.SEMANTIC_GUIDANCE.RULE_TO_TECHNICAL, et une fiche dans guidance.TECHNICAL_RISKS.adapters/ et
enregistrez-le dans adapters/__init__.py.codex est un mappage précoce et au mieux. Vérifiez son contrat
d'événement par rapport à votre version de Codex avant de compter sur lui pour
bloquer quoi que ce soit."requires login" au lieu de la ligne
correspondante réelle, donc le classificateur reconstruit l'extrait lui-même à
partir du contenu du fichier en utilisant les numéros de ligne.Edit/MultiEdit, l'adaptateur claude_code reconstruit le fichier complet
après édition à partir du disque afin qu'une source contaminée et un sink introduits
par des modifications séparées soient toujours connectés — mais seules les
détections sur les lignes que l'édition a réellement touchées sont signalées.
Si un sink existe déjà et qu'une édition ultérieure n'ajoute que la source
contaminée qui l'atteint, cela ne sera pas détecté (la ligne du sink ne faisait
pas partie de la nouvelle édition). Cette reconstruction est spécifique à
Claude Code ; l'adaptateur codex ne la fait pas encore.| Vérification | Ce qu'elle détecte | Résultat |
|---|
| Injection de commande | Une entrée non assainie atteint une commande shell | Bloque |
| Injection SQL | Une entrée non assainie atteint une requête de base de données | Bloque |
| Injection NoSQL | Le corps de la requête est utilisé directement comme filtre de base de données | Bloque |
| Injection de template (SSTI) | La source du template elle-même, pas seulement ses données, provient d'une entrée utilisateur | Bloque |
| Désérialisation non sécurisée | Des données non fiables atteignent un désérialiseur dangereux (pickle, YAML non sécurisé, ...) | Bloque |
| Traversée de chemin | Une entrée non assainie atteint une lecture, écriture ou suppression de fichier | Bloque |
| XXE | Du XML non fiable est analysé avec des entités externes activées | Bloque |
| XSS | Une entrée non assainie est rendue comme HTML brut | Bloque |
| Téléchargement de fichier sans restriction | Le nom propre du fichier téléchargé est utilisé pour construire le chemin de sauvegarde | Bloque |
| SSRF | Le serveur récupère une URL qui n'est pas codée en dur | Avertit |
| Redirection ouverte | Une cible de redirection qui n'est pas codée en dur | Avertit |
| Affectation massive | L'ensemble du corps de la requête est passé à un constructeur ou à une mise à jour de modèle | Avertit |
| Données sensibles dans un corps de requête | E-mails, mots de passe, tokens, etc. lus depuis le corps de la requête | Avertit |
| Données sensibles dans une URL/requête | E-mails, mots de passe, tokens, etc. lus depuis la chaîne de requête | Avertit |
| Données sensibles dans les en-têtes | E-mails, mots de passe, tokens, etc. lus depuis les en-têtes de requête | Avertit |
| Chemin de fichier provenant d'une entrée utilisateur | Une variable, pas une chaîne codée en dur, est utilisée comme chemin de fichier | Avertit |
| Arguments CLI | Des données proviennent d'arguments de ligne de commande | Avertit |
| Entrée standard | Des données proviennent de stdin | Avertit |
| Variables d'environnement | Des données proviennent d'une variable d'environnement | Avertit |
| Action GitHub non épinglée | Un workflow utilise un tag mutable (@v4) au lieu d'un SHA de commit | Avertit |
pull_request_target non sécurisé | Un workflow utilise le déclencheur pull_request_target | Avertit |
| Journalisation d'identifiants | Un mot de passe, une clé API ou un token est passé à print/console.log/un journal | Avertit |
| Secret codé en dur | Une variable nommée comme un secret se voit attribuer une valeur littérale réaliste | Avertit |
| Le fichier est sauvegardé, le terminal affiche un avertissement + des conseils |
| L'entrée utilisateur circule non assainie vers un sink critique (requête SQL/NoSQL, commande shell, moteur de template, désérialiseur, analyseur XML, chemin de fichier, nom de fichier téléchargé ou sortie HTML brute) | Le fichier n'est pas sauvegardé — Claude Code est informé de la raison |