Votre poste de développement contient des clés SSH sans passphrase, des tokens GitHub en clair dans l’historique shell, des credentials AWS dans des fichiers .env et du SSL désactivé dans Git — et personne ne le vérifie.
Bagel est un scanner open source qui inventorie ces risques en lecture seule, sans jamais exfiltrer les valeurs des secrets. Il produit un rapport structuré JSON avec des remédiations actionnables pour chaque finding.
Ce guide vous apprend à installer Bagel, lancer votre premier scan, interpréter les résultats et intégrer le scanner dans vos pipelines CI. Il s’adresse aux développeurs et aux équipes sécurité qui veulent auditer la posture de leurs postes de travail.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ce qu’est Bagel et pourquoi scanner les postes développeurs
- Les 9 sondes (probes) et les 8 détecteurs de secrets
- Comment installer et lancer un premier scan
- Comment interpréter et prioriser les findings
- Les remédiations concrètes par type de problème
- L’intégration CI avec le mode
--strict
Qu’est-ce que Bagel ?
Section intitulée « Qu’est-ce que Bagel ? »Bagel est une CLI cross-platform (macOS, Linux, Windows) développé en Go par BoostSecurity.io. Il inspecte le poste de travail d’un développeur et produit un rapport structuré des configurations risquées et des métadonnées de secrets — sans jamais collecter les valeurs réelles.
L’analogie est simple : Bagel fait pour votre poste développeur ce que Lynis fait pour un serveur Linux — un audit automatisé qui identifie les écarts par rapport aux bonnes pratiques de sécurité. La différence est que Bagel cible spécifiquement les outils de développement : Git, SSH, npm, cloud CLIs, IDEs, historique shell.
| Aspect | Détail |
|---|---|
| Objectif | Inventorier les configurations risquées et les secrets exposés sur les postes développeurs |
| Approche | Lecture seule — aucune modification, aucune exfiltration de secrets |
| Sondes | 9 probes : Git, SSH, npm, env, shell_history, cloud, JetBrains, GitHub CLI, AI CLI |
| Détecteurs | 8 : GitHub token, npm token, AI service, HTTP auth, SSH key, cloud credentials, generic API key, JWT |
| Sortie | JSON structuré ou table lisible |
| CI | Mode --strict (exit code 2 si findings détectés) |
| Licence | GPL-3.0 |
| Langage | Go |
Pourquoi scanner les postes développeurs ?
Section intitulée « Pourquoi scanner les postes développeurs ? »Les attaques supply chain modernes ciblent de plus en plus les postes de développement plutôt que les serveurs de production. Un poste développeur compromis donne accès à :
- Le code source — repos privés, propriété intellectuelle, secrets hardcodés
- L’infrastructure — credentials AWS/GCP/Azure, accès Kubernetes, consoles cloud
- La supply chain — tokens npm/PyPI pour publier des packages malveillants, accès aux pipelines CI/CD
Les risques les plus courants sont invisibles au quotidien :
| Risque | Exemple | Impact |
|---|---|---|
| Clé SSH sans passphrase | ~/.ssh/id_ed25519 non chiffrée | Accès à tous les serveurs et repos Git si le poste est compromis |
| Token dans l’historique shell | export GITHUB_TOKEN=ghp_... dans .zsh_history | Extraction triviale par un malware ou un script malveillant |
| SSL désactivé dans Git | http.sslVerify=false | Attaque man-in-the-middle sur les pulls/pushes |
| Credentials cloud en clair | ~/.aws/credentials avec access key | Accès complet au compte AWS |
Credentials dans .env | API_KEY=sk-... en clair | Exposition via un commit accidentel ou un accès fichier |
Bagel automatise la détection de tous ces risques en une seule commande.
Prérequis
Section intitulée « Prérequis »- Un système Linux, macOS ou Windows
- Accès à un terminal (bash, zsh, PowerShell)
- curl ou wget pour télécharger le binaire (ou Homebrew sur macOS)
- Optionnel : jq pour formater la sortie JSON
Installation
Section intitulée « Installation »Trois méthodes sont disponibles selon votre système.
Linux (x86_64 et ARM64)
Section intitulée « Linux (x86_64 et ARM64) »# x86_64curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Linux_x86_64.tar.gz | tar xzsudo mv bagel /usr/local/bin/
# ARM64curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Linux_arm64.tar.gz | tar xzsudo mv bagel /usr/local/bin/macOS (Homebrew)
Section intitulée « macOS (Homebrew) »brew tap boostsecurityio/tapbrew install bagelVérifier l’installation
Section intitulée « Vérifier l’installation »bagel versionRésultat attendu :
Version: 0.2.0Commit: 80fcbcaae2b4d0eb1db8dd2d6b312634a8be18a5Built At: 2026-02-12T14:02:03ZLes 9 sondes (probes)
Section intitulée « Les 9 sondes (probes) »Bagel organise son analyse en 9 sondes (probes), chacune focalisée sur un domaine du poste développeur.
Sondes de configuration
Section intitulée « Sondes de configuration »Ces sondes vérifient les réglages de sécurité des outils de développement.
| Sonde | Ce qu’elle vérifie | Findings typiques |
|---|---|---|
| git | Configuration Git globale | SSL désactivé, credential.helper=store, protocols dangereux, fsck désactivé, hooks personnalisés |
| ssh | Configuration SSH et clés | StrictHostKeyChecking=no, ForwardAgent=yes, clés privées sans passphrase, permissions trop permissives |
| npm | Configuration npm/Yarn | strict-ssl=false, registres HTTP (non HTTPS), tokens dans .npmrc |
Sondes de détection de secrets
Section intitulée « Sondes de détection de secrets »Ces sondes recherchent les credentials exposées dans les fichiers du poste.
| Sonde | Ce qu’elle scanne | Findings typiques |
|---|---|---|
| env | Variables d’environnement, .bashrc, .zshrc, fichiers .env | Tokens API, credentials cloud en variables d’environnement |
| shell_history | .bash_history, .zsh_history | Commandes contenant des tokens, mots de passe, clés API |
| cloud | ~/.aws/, ~/.config/gcloud/, config Azure | Access keys AWS, clés API GCP, storage keys Azure |
| jetbrains | Fichiers de configuration des IDE JetBrains | Secrets dans les configurations de run/debug |
| ai_cli | Fichiers d’outils IA CLI (Gemini, Codex, Claude, OpenCode) | Clés API OpenAI, Anthropic, Hugging Face |
Sonde d’authentification
Section intitulée « Sonde d’authentification »| Sonde | Ce qu’elle vérifie | Findings typiques |
|---|---|---|
| gh | GitHub CLI (gh) | Sessions authentifiées actives, tokens d’accès |
Les 8 détecteurs de secrets
Section intitulée « Les 8 détecteurs de secrets »Les détecteurs sont des patterns réutilisables que les sondes utilisent pour identifier les types de secrets. Chaque détecteur reconnaît des formats spécifiques.
| Détecteur | Secrets détectés | Exemples de patterns |
|---|---|---|
| github-token | Tokens GitHub (6 types) | ghp_ (Classic PAT), github_pat_ (Fine-grained), gho_, ghu_, ghs_, ghr_ |
| npm-token | Tokens npm | npm_* |
| ai-service | Clés API de services IA | sk- (OpenAI), sk-ant- (Anthropic), hf_ (Hugging Face) |
| http-auth | Credentials HTTP | Bearer tokens, Basic Auth, X-API-Key, http://user:pass@host |
| ssh-private-key | Clés privées SSH | RSA, DSA, EC, OPENSSH, PKCS8 — détecte chiffré vs non chiffré |
| cloud-credentials | Credentials cloud | AKIA* (AWS), AIza* (GCP), Azure Storage Key |
| generic-api-key | Secrets génériques | Chaînes à haute entropie (analyse entropie de Shannon) |
| jwt | JSON Web Tokens | Préfixe eyJ avec structure JWT standard |
Premier scan
Section intitulée « Premier scan »Passons à la pratique. Lançons un premier scan et analysons les résultats.
Scan rapide en format table
Section intitulée « Scan rapide en format table »Le format table donne un aperçu lisible directement dans le terminal :
bagel scan -f tableRésultat typique (données anonymisées) :
┌──────────────┬─────────────────────┐│ PROPERTY │ VALUE │├──────────────┼─────────────────────┤│ Hostname │ dev-laptop ││ OS │ linux ││ Architecture │ amd64 ││ User │ dev ││ Scan Time │ 2026-03-06 10:57:02 ││ Duration │ 4.832s │└──────────────┴─────────────────────┘
Findings: 30
┌────┬──────────┬───────────────┬─────────────────────────────────────────────┐│ # │ SEVERITY │ PROBE │ TITLE │├────┼──────────┼───────────────┼─────────────────────────────────────────────┤│ 1 │ critical │ cloud │ Cloud Credential Detected (AWS Access Key) ││ 2 │ critical │ ssh │ Unencrypted SSH Private Key (OPENSSH) ││ 3 │ critical │ env │ AI Service API Key Detected (OpenAI) ││ 4 │ critical │ shell_history │ GitHub Token Detected (Classic PAT) ││ 5 │ high │ env │ Generic API Key Detected (entropy: 4.90) ││ 6 │ high │ shell_history │ Generic API Key Detected (entropy: 5.12) ││ ...│ ... │ ... │ ... │└────┴──────────┴───────────────┴─────────────────────────────────────────────┘Ce scan — qui a duré moins de 5 secondes — a trouvé 30 findings dont 7 critiques. Les sondes shell_history et env sont celles qui remontent le plus de résultats, ce qui est typique d’un poste de développement actif.
Scan JSON avec sauvegarde
Section intitulée « Scan JSON avec sauvegarde »Le format JSON est plus adapté à l’analyse programmatique et à l’intégration CI :
bagel scan -o rapport-bagel.jsonLe fichier JSON contient trois sections principales :
{ "metadata": { "version": "0.1.0", "timestamp": "2026-03-06T10:57:02Z", "duration": "4.832s" }, "host": { "hostname": "dev-laptop", "os": "linux", "arch": "amd64", "username": "dev", "system": { "os_version": "Ubuntu 24.04 LTS", "kernel_version": "6.8.0-100-generic", "cpu_cores": 16, "ram_total_gb": 32 } }, "findings": [ { "id": "ssh-private-key-openssh", "probe": "ssh", "severity": "critical", "title": "Unencrypted SSH Private Key Detected (OPENSSH)", "message": "An unencrypted OPENSSH SSH private key was detected...", "path": "file:/home/dev/.ssh/id_ed25519", "metadata": { "detector_name": "ssh-private-key", "token_type": "openssh-private-key" } } ]}Analyser les résultats avec jq
Section intitulée « Analyser les résultats avec jq »Pour extraire rapidement un résumé par sévérité :
cat rapport-bagel.json | jq '[.findings[] | .severity] | group_by(.) | map({severity: .[0], count: length})'Résultat :
[ { "severity": "critical", "count": 7 }, { "severity": "high", "count": 23 }]Pour lister uniquement les findings critiques :
cat rapport-bagel.json | jq '.findings[] | select(.severity == "critical") | {id, probe, title}'Pour compter les findings par sonde :
cat rapport-bagel.json | jq '[.findings[] | .probe] | group_by(.) | map({probe: .[0], count: length})'Interpréter et prioriser les findings
Section intitulée « Interpréter et prioriser les findings »Tous les findings ne se valent pas. Voici comment les prioriser.
Sévérité critique — à traiter en priorité
Section intitulée « Sévérité critique — à traiter en priorité »Les findings critical indiquent des risques d’exploitation immédiate :
| Finding | Risque réel | Urgence |
|---|---|---|
ssh-private-key-openssh (non chiffré) | Si le poste est compromis, l’attaquant accède à tous les serveurs | Immédiat — ajouter une passphrase |
cloud-credential-aws-access-key-id | Accès complet au compte AWS | Immédiat — rotation de la clé + utilisation d’un profil SSO |
ai-service-openai-api-key | Consommation frauduleuse de l’API + fuite de données | Immédiat — rotation de la clé |
github-token-classic-pat | Accès aux repos privés, push de code malveillant | Immédiat — révoquer et recréer en fine-grained |
http-auth-basic-auth-url | Credentials en clair dans l’historique shell | Rapide — nettoyer l’historique |
Sévérité haute — à planifier
Section intitulée « Sévérité haute — à planifier »Les findings high indiquent des expositions qui nécessitent un accès préalable pour être exploitées :
| Finding | Risque | Action |
|---|---|---|
generic-api-key (haute entropie) | Possible faux positif, mais les vrais tokens sont mélangés | Vérifier chaque occurrence manuellement |
Tokens dans les fichiers .env | Exfiltration si le fichier est commité ou lu par un processus malveillant | Utiliser un gestionnaire de secrets |
Remédiation par type de finding
Section intitulée « Remédiation par type de finding »Voici les actions concrètes pour les findings les plus courants.
Clé SSH sans passphrase
Section intitulée « Clé SSH sans passphrase »Le finding ssh-private-key-openssh signale une clé privée non chiffrée. Ajoutez une passphrase sans recréer la clé :
# Ajouter une passphrase à une clé existantessh-keygen -p -f ~/.ssh/id_ed25519Pour les nouvelles clés, utilisez toujours Ed25519 avec passphrase :
ssh-keygen -t ed25519 -C "dev@company.com"Credentials cloud en clair
Section intitulée « Credentials cloud en clair »Le finding cloud-credential-aws-access-key-id signale des access keys AWS dans ~/.aws/credentials. Migrez vers AWS SSO (IAM Identity Center) :
# Configurer AWS SSO (remplace les access keys statiques)aws configure ssoSi vous devez conserver des access keys, chiffrez le fichier credentials et assurez-vous que la rotation automatique est en place.
Tokens dans l’historique shell
Section intitulée « Tokens dans l’historique shell »Les findings shell_history signalent des secrets tapés dans le terminal. Nettoyez l’historique et évitez que ça se reproduise :
# Supprimer les lignes contenant des tokens de l'historiquegrep -n "ghp_\|sk-\|AKIA\|Bearer " ~/.zsh_history | head -20
# Nettoyer l'historique zsh (sauvegarde d'abord)cp ~/.zsh_history ~/.zsh_history.baksed -i '/ghp_\|sk-\|AKIA/d' ~/.zsh_historyPour éviter que les secrets finissent dans l’historique :
# Ajouter dans ~/.zshrc — les commandes précédées d'un espace ne sont pas historiséessetopt HIST_IGNORE_SPACE
# Utilisation : un espace avant la commande export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxGit SSL désactivé
Section intitulée « Git SSL désactivé »Le finding git-ssl-verify-disabled signale que la vérification SSL est désactivée. Corrigez-le :
git config --global http.sslVerify true
# Si vous avez un proxy d'entreprise avec certificat auto-signé :git config --global http.sslCAInfo /chemin/vers/ca-bundle.crtGit credential.helper=store
Section intitulée « Git credential.helper=store »Le finding git-credential-plaintext signale que Git stocke les mots de passe en clair dans ~/.git-credentials. Utilisez un helper sécurisé :
# Linux — utiliser libsecret (GNOME Keyring)git config --global credential.helper libsecret
# Linux — ou utiliser un cache temporaire (1h)git config --global credential.helper 'cache --timeout=3600'
# macOS — utiliser le trousseaugit config --global credential.helper osxkeychainConfiguration avancée
Section intitulée « Configuration avancée »Bagel utilise un fichier YAML pour personnaliser le scan. Il cherche bagel.yaml dans cet ordre :
- Chemin spécifié avec
--config - Répertoire courant (
./bagel.yaml) - Répertoire de configuration système (
~/.config/bagel/bagel.yaml)
Désactiver une sonde
Section intitulée « Désactiver une sonde »Si une sonde génère trop de faux positifs ou n’est pas pertinente pour votre environnement :
version: 1probes: shell_history: enabled: false # Trop de faux positifs generic-api-key dans l'historique jetbrains: enabled: false # Pas d'IDE JetBrains sur ce posteExclure des variables d’environnement
Section intitulée « Exclure des variables d’environnement »Pour éviter les faux positifs sur des variables connues :
version: 1privacy: exclude_env_prefixes: - "LESS" - "LS_COLORS" - "TERM"Scan complet avec toutes les sondes
Section intitulée « Scan complet avec toutes les sondes »La configuration par défaut active toutes les sondes. Si vous avez modifié la config et voulez revenir au scan complet :
version: 1probes: git: enabled: true ssh: enabled: true npm: enabled: true env: enabled: true shell_history: enabled: true cloud: enabled: true jetbrains: enabled: true gh: enabled: true ai_cli: enabled: trueRaccourcis en ligne de commande
Section intitulée « Raccourcis en ligne de commande »# Scan avec sortie table (lisible)bagel scan -f table
# Sauvegarder le rapportbagel scan -o rapport.json
# Mode CI (échoue si findings)bagel scan --strict
# Forcer la reconstruction de l'index fichierbagel scan --no-cache
# Mode debugbagel scan --verbose --no-progress
# Combiner les optionsbagel scan --strict --no-progress -f json -o rapport.jsonDépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
bagel: command not found | Binaire pas dans le PATH | Vérifier : ls /usr/local/bin/bagel ou ajouter le chemin au PATH |
| Scan très lent (> 30s) | Nombreux fichiers dans le home | Utiliser --no-progress pour voir les logs, vérifier qu’un dossier volumineux n’est pas scanné |
Trop de generic-api-key | Faux positifs sur des hashes/UUIDs | Désactiver shell_history dans la config ou filtrer avec jq |
finding_count: 0 | Aucune configuration risquée détectée | Vérifier que les fichiers ciblés existent (~/.gitconfig, ~/.ssh/) |
Erreur permission denied | Fichiers inaccessibles en lecture | Bagel ne scanne que les fichiers lisibles par l’utilisateur courant — c’est normal |
| Le cache n’est pas utilisé | Fichiers modifiés depuis le dernier scan | Comportement attendu — Bagel détecte les modifications et reconstruit l’index |
exit code 2 en CI | Mode --strict + findings détectés | Comportement attendu — corriger les findings ou ajuster la configuration |
À retenir
Section intitulée « À retenir »-
Bagel scanne votre poste développeur en lecture seule pour identifier les configurations risquées (Git, SSH, npm) et les métadonnées de secrets — sans jamais collecter les valeurs réelles.
-
9 sondes couvrent l’essentiel de l’environnement développeur : Git, SSH, npm, variables d’environnement, historique shell, credentials cloud, JetBrains, GitHub CLI et outils IA.
-
8 détecteurs identifient les types de secrets par pattern (GitHub tokens, AWS keys, OpenAI keys, JWT) et par analyse d’entropie pour les secrets génériques.
-
Les findings les plus critiques sont les clés SSH sans passphrase, les credentials cloud en clair et les tokens dans l’historique shell — corrigez-les en priorité.
-
Le mode
--strict(exit code 2) permet d’intégrer Bagel dans un pipeline CI pour vérifier la posture des runners ou des images de développement. -
La configuration YAML permet de désactiver les sondes non pertinentes et d’exclure les faux positifs, pour un rapport ciblé et actionnable.