Kingfisher est un scanner de secrets publié par MongoDB, sous licence Apache-2.0 et écrit en Rust, qui ne s'arrête pas à la détection : il vérifie qu'un secret est actif, cartographie ce qu'il permet d'atteindre, puis peut le révoquer. Là où les trois scanners précédents du module s'arrêtent au constat, à la vérification ou, pour TruffleHog, à une analyse des permissions, Kingfisher enchaîne cinq gestes dans un seul outil : détecter, valider, cartographier, trier, révoquer. Cette leçon parcourt les cinq, en insistant sur les trois derniers, que Gitleaks, Betterleaks et TruffleHog ne couvrent pas, ou pas de la même façon.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Scanner avec Kingfisher un dossier, l'historique d'un dépôt et une organisation, puis lire le résultat.
- Distinguer un secret actif, inactif, inconclusif et seulement présumé valide.
- Cartographier le rayon d'impact d'un secret valide avec
--blast-radius, et savoir quand le faire. - Révoquer un secret pris en charge avec
kingfisher revoke, en connaissant les limites du geste. - Brancher l'outil dans un hook pre-commit et dans GitHub Actions, en exploitant ses codes de sortie.
- Relier la leçon au SOCLE : l'exigence SOCLE-SEC-GEN-6, détection de fuite de secrets et procédure de réponse, trouve ici son outillage de détection et de réponse.
Prérequis
Section intitulée « Prérequis »Cette leçon suppose acquis ce que les trois leçons précédentes du module enseignent : pourquoi un secret commité reste lisible dans l'historique Git, ce qu'est un faux positif, et pourquoi on valide un secret auprès de son fournisseur. Si ces notions sont floues, lisez d'abord Gitleaks puis TruffleHog, et le guide sur les secrets dans le code et l'historique Git. Il faut aussi savoir lire un fichier YAML et lancer des commandes dans un terminal.
Côté poste, prévoyez Docker, Homebrew ou uv, au choix, et un dépôt Git jetable. Aucun compte chez un fournisseur n'est nécessaire pour les premiers essais : le secret utilisé ici est un faux.
Cinq gestes dans un seul outil
Section intitulée « Cinq gestes dans un seul outil »Un scanner classique rend une liste de candidats : des chaînes qui ressemblent à une clé. Kingfisher prolonge cette liste en cinq étapes, que sa documentation résume par « Detect, Validate, Map, Triage, Revoke ». Le schéma ci-dessous les place dans l'ordre, avec la commande qui porte chacune. Regardez surtout la deuxième boîte, qui fait passer d'une liste de candidats à une liste de secrets prouvés, et la dernière, en rouge, la seule à modifier quelque chose chez un tiers.
Les deux premiers gestes existent ailleurs, sous une forme voisine. La validation est celle que TruffleHog appelle vérification et que Betterleaks active avec son option dédiée : elle envoie le secret au fournisseur pour savoir s'il fonctionne. TruffleHog sait aussi analyser les permissions d'une partie des identifiants. Ce que Kingfisher réunit, d'après son README, c'est la cartographie de l'accès, un visualiseur de rapport et la révocation pour les fournisseurs pris en charge, le tout dans la version libre, sans offre payante séparée.
Le dépôt de Kingfisher publie aussi des durées de scan comparées, où l'outil arrive premier sur chaque dépôt testé. Elles viennent d'une machine macOS à 16 cœurs et ne constituent pas un benchmark de la version actuelle, comme le précise le dépôt lui-même : mesurez sur vos propres dépôts avant de vous y fier.
Installer Kingfisher
Section intitulée « Installer Kingfisher »Trois voies suffisent pour démarrer. Homebrew et le paquet PyPI installent le binaire sur le poste ; l'image de conteneur évite toute installation et convient à la CI.
# Homebrew (macOS, Linux)brew install kingfisher
# Paquet PyPI qui fournit le binaireuv tool install kingfisher-bin==2.16.0
# Image de conteneur : tag de version et digestdocker run --rm \ ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa \ --versionLa commande affiche la version installée.
kingfisher 2.16.0Les exemples suivants appellent kingfisher directement. L'image demande trois réglages de plus, faute de quoi le rapport est perdu ou refusé : elle s'exécute avec l'utilisateur 10001 et le répertoire de travail /app, qui n'est pas votre dossier. Montez donc le dépôt dans /src, passez votre propre identifiant avec -u pour que le rapport vous appartienne, et écrivez-le sous /src.
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD":/src \ ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa \ scan /src --format json --output /src/findings.jsonLe fichier findings.json apparaît dans le dossier courant. Pour le visualiseur, le serveur doit écouter sur toutes les interfaces du conteneur (--address 0.0.0.0), et le port est publié sur la boucle locale de votre poste seulement (-p 127.0.0.1:7890:7890) : aucun autre ordinateur du réseau ne peut le joindre. Le conteneur n'a pas de navigateur, ouvrez http://127.0.0.1:7890 vous-même.
docker run --rm -u "$(id -u):$(id -g)" -p 127.0.0.1:7890:7890 -v "$PWD":/src \ ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa \ view /src/findings.json --address 0.0.0.0Premier scan sur un faux manifeste
Section intitulée « Premier scan sur un faux manifeste »Pour voir les statuts de validation sans risque, créez un dépôt jetable avec un faux manifeste Kubernetes. Le jeton ci-dessous a la forme d'un jeton personnel GitHub mais ne correspond à aucun compte : le fournisseur le rejettera.
mkdir demo-kingfisher && cd demo-kingfishergit init --quietcat > secret.yaml <<'EOF'apiVersion: v1kind: Secretmetadata: name: ci-githubstringData: token: ghp_R7kQ2mZ9xT4vB8nW1cL6yD3sF5hJ0aPeUgXiEOFgit add secret.yamlgit -c user.name=demo -c user.email=demo@example.org commit --quiet -m "ajoute un faux secret"Lancez ensuite le scan. Par défaut, Kingfisher scanne l'historique complet du dépôt (--git-history full) et tente la validation en direct. Le code de sortie importe autant que l'affichage, c'est pourquoi on l'affiche.
kingfisher scan . --format json --output findings.jsonecho "code de sortie : $?"Le scan a trouvé quelque chose. Le code 200 signifie « résultats visibles ». Le code 205, « résultats visibles et validés », est réservé aux secrets prouvés actifs : le fournisseur a rejeté le faux jeton, il ne s'applique donc pas ici.
code de sortie : 200Le rapport findings.json porte alors, pour le faux jeton, le statut de validation verified_inactive et la réponse du fournisseur (extrait) :
{"outcome":"verified_inactive","status":"Inactive Credential","response":"{\"reason\":\"Unauthorized\",\"result\":\"invalid\"}"}Avec --no-validate, le même scan rend aussi le code 200, mais le statut devient not_attempted (« Not Attempted ») et aucune requête ne part vers GitHub.
Ouvrez le rapport pour lire le statut. Dans le JSON, le champ à utiliser en automatisation est finding.validation.outcome, qui porte une valeur stable, alors que le libellé affiché peut changer.
kingfisher view findings.jsonLe visualiseur démarre en local sur 127.0.0.1:7890 et ouvre le navigateur (avec l'image, utilisez la commande view du conteneur donnée plus haut). Comme le jeton est faux, le résultat attendu est le statut Inactive Credential, de valeur verified_inactive. Le rapport JSON contient exactement cette information, que vous pouvez aussi lire sans navigateur :
grep -o '"outcome":"[a-z_]*"' findings.json"outcome":"verified_inactive"Si vous obtenez le statut Inconclusive Validation à la place, le fournisseur n'a pas répondu (poste hors ligne, limite de débit) : voir le dépannage plus bas. Supprimez ensuite le dépôt d'essai.
cd .. && rm -rf demo-kingfisherLire le verdict de validation
Section intitulée « Lire le verdict de validation »La validation est le cœur de l'outil, et son résultat ne se réduit pas à « actif ou non ». La documentation de Kingfisher distingue plusieurs statuts, et le tri des alertes en dépend. Le tableau ci-dessous reprend les principaux ; la valeur machine est celle à tester dans un script.
| Statut affiché | Valeur machine | Ce que cela prouve |
|---|---|---|
| Active Credential | verified_active | Un validateur a prouvé que le secret fonctionne : à traiter en premier. |
| Inactive Credential | verified_inactive | Le fournisseur a rejeté le secret : il est mort, mais reste à nettoyer. |
| Inconclusive Validation | unavailable | La vérification n'a pas abouti (délai, limite, erreur serveur) : ni preuve d'activité, ni d'inactivité. |
| Assumed Valid (Not Live-Validated) | assumed | Le secret est très probablement réel, mais personne ne l'a testé en direct. |
| Not Attempted | not_attempted | Aucune validation produite : pas de validateur pour cette règle, ou --no-validate. |
Un filtre sélectionne ce qui reste dans le rapport. L'option --validation-filter accepte trois valeurs : all, qui garde tout et est la valeur par défaut ; active, qui ne garde que les secrets prouvés actifs ; et actionable, qui ajoute les secrets présumés valides et ceux qu'un calcul local a reconnus. L'option --only-valid est un alias de --validation-filter active, et les deux ne se combinent pas.
# Ne garder que les secrets prouvés actifskingfisher scan . --validation-filter active --format jsonQuand tous les secrets du dépôt sont morts, le rapport obtenu a un tableau findings vide ({"findings":[],"audit":{...). Sur le faux jeton, le code de sortie vaut pourtant encore 200, parce que le code compte les trouvailles avant le filtre. Pour décider d'un blocage, testez donc le contenu du rapport ou le code 205, et non le code 200 seul.
Pourquoi ne pas filtrer systématiquement sur active ? Parce qu'un secret inactif n'est pas forcément sans danger : copié ailleurs, il peut encore ouvrir un autre service, et l'historique le garde lisible. Le filtre sert à ordonner les corrections, pas à effacer les trouvailles.
Cartographier le rayon d'impact
Section intitulée « Cartographier le rayon d'impact »Savoir qu'une clé AWS est active ne dit pas si elle ouvre un bucket de test ou toute la production. L'option --blast-radius, qui a pour alias --access-map, répond à cette question pour les types de secrets pris en charge : elle identifie le propriétaire du secret (utilisateur, rôle, compte de service), ses permissions enregistrées et les ressources visibles. Pour AWS, elle suit aussi les rôles que la clé peut endosser ; pour GCP, les comptes de service qu'elle peut usurper.
kingfisher scan . --only-valid --blast-radius --format json --output findings.jsonLe rapport JSON est le même que d'habitude, enrichi d'un champ access_map pour chaque secret actif d'un fournisseur pris en charge. La sortie dépend donc d'un secret réellement actif : la cartographie interroge l'API du fournisseur avec le secret, et un faux jeton ne donne rien à cartographier. Avec le faux jeton de la leçon, la commande rend le code 200 et un rapport au tableau findings vide, sans aucun champ access_map, parce que --only-valid écarte tout ce qui n'est pas prouvé actif. Pour voir une vraie cartographie, il faut un secret actif et un compte que vous avez le droit d'inspecter.
Trois précisions évitent de mal interpréter le résultat. La cartographie est en lecture seule et « au mieux » : un accès non observé n'est pas un accès impossible, car les politiques et les chemins candidats donnent du contexte sans prouver chaque accès. Elle lance des requêtes réseau en plus de la validation, et la documentation précise de ne l'utiliser que si vous êtes autorisé à inspecter le compte visé. Enfin, elle ne s'applique qu'aux fournisseurs pris en charge : la documentation en compte quarante-trois à ce tag, et la liste fait foi, pas ce chiffre.
Pour inspecter un seul secret connu sans scanner de dépôt, la commande autonome kingfisher blast-radius produit la même cartographie à partir d'une règle et du secret fourni directement. Utilisez --aws-region ou --gcp-project pour élargir la découverte à d'autres régions ou projets. Avec le faux jeton de la leçon, kingfisher blast-radius --rule github-pat <jeton> échoue proprement, avec le code de sortie 1 :
Error: Blast-radius mapping failed for all rules matching 'github-pat':- betterleaks.github-pat: Identity mapping failed: GitHub access-map: user lookup failed with HTTP 401 UnauthorizedRévoquer un secret
Section intitulée « Révoquer un secret »Quand un secret actif est trouvé et que son propriétaire est introuvable, parti ou injoignable, attendre la rotation fait durer l'exposition. La commande kingfisher revoke désactive directement le secret auprès du fournisseur, sans passer par l'employé qui l'a créé. C'est un geste explicite : aucun scan ne révoque quoi que ce soit.
kingfisher revoke --rule github-pat "$JETON_COMPROMIS"La commande affiche un message de succès ou d'échec par règle appliquée. Le code de sortie vaut 0 si au moins une règle a révoqué le secret, et 1 si toutes ont échoué ou si une erreur est survenue. Avec le faux jeton de la leçon (ghp_R7kQ...), la sortie de 2.16.0 est :
Rule: Uncovered a GitHub Personal Access Token, potentially leading to unauthorized repository access and sensitive content exposure. (betterleaks.github-pat)Result: REVOKEDStatus: 202Response: {
}Le code de sortie est 0. Retenez ce que cela prouve : le fournisseur a accepté la demande (HTTP 202), pas que le jeton existait. Un faux jeton obtient le même REVOKED. Après une révocation, vérifiez donc le statut du secret chez le fournisseur au lieu de vous fier au seul message.
La révocation est volontairement conservatrice. Kingfisher ne propose l'action que lorsqu'il peut identifier la clé exacte et réunir les valeurs que le fournisseur exige ; à ce tag, la documentation compte 34 règles de révocation pour 15 familles de fournisseurs (AWS, GitHub, GitLab, npm, Cloudflare, Hugging Face, entre autres), et le fichier de capacités du dépôt est la liste de référence. Pour un secret hors liste, il faut passer par la console du fournisseur.
Choisir la cible du scan
Section intitulée « Choisir la cible du scan »Un dépôt local n'est qu'une des cibles. La commande kingfisher scan accepte des sous-commandes qui énumèrent des organisations, des stockages et des outils de collaboration, chacune avec son jeton dans une variable d'environnement préfixée KF_. Le tableau donne les plus utiles ; la liste complète est dans le guide d'intégrations du dépôt.
| Cible | Commande | Authentification |
|---|---|---|
| Dossier ou dépôt local | kingfisher scan . | aucune |
| Dépôt distant | kingfisher scan https://github.com/org/depot.git | KF_GITHUB_TOKEN s'il est privé |
| Organisation GitHub | kingfisher scan github --organization org | KF_GITHUB_TOKEN |
| Groupe GitLab | kingfisher scan gitlab --group groupe --include-subgroups | KF_GITLAB_TOKEN |
| Image de conteneur | kingfisher scan docker image:tag | KF_DOCKER_TOKEN si le registre est privé |
| Bucket S3 | kingfisher scan s3 mon-bucket | --profile ou KF_AWS_KEY et KF_AWS_SECRET |
| Tickets et wikis | kingfisher scan jira et kingfisher scan confluence | KF_JIRA_TOKEN, KF_CONFLUENCE_TOKEN |
| Messages | kingfisher scan slack "api_key OR password" | KF_SLACK_TOKEN |
Avant de lancer le scan d'une organisation, l'option --list-only affiche les dépôts qui seraient scannés, sans rien scanner. C'est un bon réflexe : un jeton qui voit mille dépôts les scannerait tous, et mieux vaut le savoir avant.
KF_GITHUB_TOKEN="$TOKEN_LECTURE" kingfisher scan github --organization mon-org --list-onlyLa commande affiche l'URL de clonage de chaque dépôt de l'organisation visible avec ce jeton, une par ligne, sans aucun résultat de scan. Avec trois dépôts, la sortie de 2.16.0 est :
https://github.com/mon-org/api-facturation.githttps://github.com/mon-org/infra-terraform.githttps://github.com/mon-org/site-vitrine.gitCompter les lignes donne le nombre de dépôts que le scan parcourrait. La commande interroge l'API de la forge, elle ne fonctionne donc pas hors ligne. Si votre poste n'a pas de réseau, vous obtenez le code de sortie 1 et une erreur de résolution DNS au lieu de la liste.
Sur l'historique, la valeur par défaut est de tout parcourir. Trois options le bornent : --git-history none scanne seulement l'état actuel des fichiers ; --since-commit <ref> scanne les commits ajoutés depuis une référence, ce qui convient à une revue de pull request ; --staged scanne les changements en attente de commit. Les options --path-prefix, --skip-path-prefix et --file-extension restreignent aussi les chemins.
Choisir le format de sortie
Section intitulée « Choisir le format de sortie »Le format se règle avec --format, et --output écrit dans un fichier au lieu de l'écran. Quatre formats couvrent l'essentiel : json pour les scripts, sarif pour l'onglet de sécurité d'une forge, html pour un rapport d'audit autonome, et pretty pour le terminal. Un cinquième, toon, est conçu pour être donné à un agent IA.
Le visualiseur ne se limite pas aux rapports Kingfisher : il lit aussi les rapports de Gitleaks et de TruffleHog et les fusionne en dédoublonnant. Si vous avez déjà ces scanners en place, kingfisher view gitleaks.json trufflehog.jsonl donne un tableau de tri commun sans changer vos pipelines.
Brancher Kingfisher dans la chaîne
Section intitulée « Brancher Kingfisher dans la chaîne »Les codes de sortie rendent Kingfisher utilisable en automatisation : ils distinguent un secret simplement trouvé d'un secret prouvé actif.
| Code | Signification |
|---|---|
0 | Aucun résultat visible. |
200 | Des résultats visibles. |
205 | Des résultats visibles et validés. |
1 | Erreur fatale du scan. |
2 | Arguments invalides. |
3 | Rien à scanner. |
Ces codes autorisent une politique en deux temps. Bloquer la fusion sur 205 seulement évite de gêner les équipes pour des secrets morts, tandis que bloquer sur 200 aussi est plus strict et adapté à un dépôt sensible. Un scan peut continuer après une erreur de lecture et rendre un code de succès avec une couverture partielle : en production, vérifiez aussi audit.summary.scan_partial et audit.summary.scan_failed dans le rapport JSON.
Hook pre-commit
Section intitulée « Hook pre-commit »Le framework pre-commit exécute des contrôles avant chaque commit. Le dépôt de Kingfisher publie bien des hooks prêts à l'emploi, mais le hook kingfisher-auto télécharge la dernière version du binaire sans en vérifier l'empreinte, et le hook kingfisher-docker tire l'image latest : aucun des deux n'est épinglé, même si rev l'est. On les écarte ici au profit d'un hook local, qui lance l'image épinglée par digest avec language: docker_image. Le framework monte alors le dépôt dans /src et passe votre identifiant d'utilisateur, ce qui règle deux des pièges de la voie Docker vus plus haut. Un troisième est propre à l'option --staged : pour scanner les fichiers indexés, Kingfisher crée un instantané avec git commit-tree, et Git refuse de le faire sans identité. Le framework ne transmet pas votre configuration Git au conteneur, d'où les quatre variables GIT_* en tête de l'entrée, qui donnent une identité de service sans rapport avec la vôtre.
repos: - repo: local hooks: - id: kingfisher name: kingfisher language: docker_image entry: >- -e GIT_AUTHOR_NAME=kingfisher -e GIT_AUTHOR_EMAIL=kingfisher@localhost -e GIT_COMMITTER_NAME=kingfisher -e GIT_COMMITTER_EMAIL=kingfisher@localhost ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa scan . --staged --quiet --no-update-check pass_filenames: falseInstallez le hook avec pre-commit install. À chaque commit, --staged limite le scan aux fichiers en attente (pass_filenames: false évite seulement que le framework ajoute leurs noms à la commande), et le commit est refusé si le code de sortie n'est pas 0. Le dépôt doit déjà contenir au moins un commit : sans lui, le scan échoue sur une erreur Git. Dans les deux cas d'échec Git (pas de commit, pas d'identité), le hook s'affiche Passed et le commit passe, secret compris : voir le dépannage.
Voici ce qu'affiche git commit dans un dépôt qui a déjà un commit, quand secret.yaml, qui contient le faux jeton de la leçon, est indexé mais pas encore commité, avec Kingfisher 2.16.0 (la sortie est raccourcie). Sans accès réseau, le fournisseur ne répond pas, d'où le statut inconclusif.
kingfisher...............................................................Failed- hook id: kingfisher- exit code: 200
GITHUB-PAT => [BETTERLEAKS.GITHUB-PAT] |Finding.........: ghp_R7kQ2mZ9xT4vB8nW1cL6yD3sF5hJ0aPeUgXi |Description.....: Uncovered a GitHub Personal Access Token, potentially leading to unauthorized repository access and sensitive content exposure. |Fingerprint.....: 667680336578602825 |Confidence......: high |Entropy.........: 5.22 |Validation......: Inconclusive Validation |__Response......: Betterleaks validation request failed |Language........: YAML |Line Num........: 6 |Path............: secret.yaml...Le code de sortie du hook vaut 200, donc le commit est refusé : git log ne montre aucun nouveau commit. Avec un accès réseau, la ligne Validation indique Inactive Credential pour ce faux jeton, et le code reste 200. Sans secret dans l'index, le hook affiche Passed et le commit est créé.
Workflow GitHub Actions
Section intitulée « Workflow GitHub Actions »Le workflow suivant scanne les commits d'une pull request avec l'image épinglée. Le SHA de base passe par une variable d'environnement plutôt que d'être inséré dans la commande, pour qu'aucune donnée du contexte GitHub ne soit interprétée comme du shell. L'étape échoue sur tout code non nul.
name: secretson: pull_request:
permissions: {}
jobs: kingfisher: runs-on: ubuntu-24.04 permissions: contents: read steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false
- name: Scanner les commits de la pull request env: BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | code=0 docker run --rm -v "$PWD":/src \ ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa \ scan /src --since-commit "$BASE_SHA" --quiet --no-update-check --format json || code=$? echo "code de sortie : $code" exit "$code"L'étape affiche code de sortie : 0 quand la pull request n'ajoute aucun secret, et code de sortie : 200 ou 205 avec une étape en échec sinon. Si le second commit de la pull request ajoute le faux jeton, le rapport JSON s'affiche d'abord, puis la dernière ligne vaut :
code de sortie : 200Si le second commit n'ajoute aucun secret, le rapport commence par {"findings":[],"audit":... et la dernière ligne vaut code de sortie : 0. Les permissions minimales, le SHA épinglé, persist-credentials: false et le passage du contexte par env suivent les règles de actionlint et de zizmor : passez ces deux outils sur vos propres workflows avant de les fusionner.
Pour ne bloquer que sur les secrets validés, remplacez la dernière ligne par un test qui sort en erreur seulement si code vaut 205. Sur une pull request venue d'un fork, la validation envoie le secret trouvé à un tiers : si le contenu n'est pas de confiance, ajoutez --no-validate.
Dépannage
Section intitulée « Dépannage »Les symptômes ci-dessous sont ceux qu'on rencontre en suivant la leçon. Deux d'entre eux se ressemblent : un code 200 alors que le rapport est vide, et un code 0 alors que Git a échoué. Dans les deux cas le code de sortie seul trompe, et c'est le rapport qui dit ce qui s'est réellement passé.
| Symptôme | Cause probable | Correction |
|---|---|---|
manifest unknown en tirant l'image | Tag écrit v2.16.0 avec un v | Utiliser ghcr.io/mongodb/kingfisher:2.16.0, sans v. |
Avec l'image, findings.json est introuvable, ou Permission denied | Sans -u, le conteneur tourne avec l'utilisateur 10001 et écrit dans /app ; son /src monté n'est pas inscriptible | Passer -u "$(id -u):$(id -g)" et --output /src/findings.json. |
kingfisher view dans le conteneur, rien dans le navigateur | Aucun port publié, ou serveur lié à 127.0.0.1 dans le conteneur | Ajouter -p 127.0.0.1:7890:7890 et --address 0.0.0.0. |
Code de sortie 3 | Aucun dépôt ou fichier à scanner (utilisateur sans dépôt, tout exclu) | Vérifier la cible avec --list-only et les exclusions. |
Code de sortie 200 alors que tout semble mort | Le code compte les trouvailles avant le filtre, donc il reste 200 même quand le rapport est vide | Ajouter --validation-filter active pour vider le rapport, puis bloquer sur le code 205 ou sur un tableau findings non vide. |
Git command failed (exit status: 128) avec --staged, et pourtant code 0 | Dépôt sans aucun commit, ou conteneur sans identité Git (le hook pre-commit ne transmet pas votre configuration) : Git ne peut pas créer l'instantané des fichiers indexés | Faire un premier commit, et ajouter -e GIT_AUTHOR_NAME=... -e GIT_AUTHOR_EMAIL=... -e GIT_COMMITTER_NAME=... -e GIT_COMMITTER_EMAIL=... avant l'image, avec -u "$(id -u):$(id -g)" hors pre-commit ; ne vous fiez pas au seul code de sortie, lancez pre-commit run --verbose pour voir l'erreur. |
Statut Inconclusive Validation | Fournisseur injoignable, délai ou limite de débit | Relancer le scan après quelques minutes ; ne pas conclure que le secret est mort. |
Statut Not Attempted partout | --no-validate actif, ou pas de validateur pour la règle | Retirer --no-validate ; pour une règle sans validateur, vérifier à la main. |
| Erreur à la combinaison des options | --only-valid et --validation-filter ensemble | Garder une seule des deux. |
| Pipeline vert alors qu'un dépôt n'a pas été lu | Scan partiel qui rend un code de succès | Lire audit.summary.scan_partial dans le rapport JSON. |
--since-commit ne trouve rien en CI | Clone peu profond sans le commit de base | Cloner avec fetch-depth: 0. |
Gitleaks, Betterleaks, TruffleHog ou Kingfisher : lequel choisir ?
Section intitulée « Gitleaks, Betterleaks, TruffleHog ou Kingfisher : lequel choisir ? »Les quatre scanners détectent des secrets, et leurs écarts portent surtout sur ce qu'ils font après la détection : vérifier, mesurer, révoquer. Kingfisher est le seul à documenter ces trois gestes ensemble dans une version stable, mais le tableau montre aussi ce que les autres font mieux ou autrement, par exemple l'étendue des sources de TruffleHog ou la sobriété de Gitleaks.
Le tableau compare les quatre scanners sur ce qui compte au moment de choisir : où ils cherchent, ce qu'ils font d'un secret trouvé et comment ils s'intègrent à une chaîne de livraison. Chaque cellule vient de la documentation de l'outil lui-même à la version indiquée en en-tête. Quand cette documentation ne dit rien d'une capacité, la cellule porte « non documenté » : cela ne prouve pas que l'outil en soit incapable, seulement que sa documentation ne l'annonce pas.
| Critère | Gitleaks 8.30.1 | Betterleaks 1.9.0 | TruffleHog 3.99.7 | Kingfisher 2.16.0 |
|---|---|---|---|---|
| Dépôt Git et historique | oui, gitleaks git (via git log -p) | oui, betterleaks git | oui, trufflehog git | oui, historique inclus |
| Dépôt distant, organisation | non documenté (trois modes : git, dir, stdin) | GitHub (organisation, utilisateur, PR, tickets, Actions, releases), GitLab (groupe, projet, merge requests), Hugging Face | GitHub (--org), GitLab, Hugging Face | GitHub, GitLab, Azure Repos, Bitbucket, Gitea, Hugging Face |
| Fichiers et répertoires | oui, gitleaks dir | oui, betterleaks dir | oui, trufflehog filesystem | oui |
| Image de conteneur | non documenté | non documenté | oui, trufflehog docker | oui, kingfisher scan docker |
| Autres sources | entrée standard | entrée standard, S3 (dont Cloudflare R2) | S3, GCS, Postman, Jenkins, Elasticsearch, CircleCI, Travis CI, syslog, entrée standard | S3, GCS, Azure Blob Storage, Jira, Confluence, Slack, Teams, Postman |
| Vérifie qu'un secret est actif | non documenté | oui, par une expression validate dans la règle, sur option seulement, --validation en 1.9.0 (-v ou --validate en version 2) ; statuts valid, invalid, revoked, unknown, error | oui, par appel à l'API du fournisseur, activé par défaut (--no-verification pour l'éteindre) | oui, activé par défaut (--no-validate pour l'éteindre) |
| Mesure le rayon d'impact | non documenté | non documenté en 1.9.0 ; la version 2 en préversion ajoute -a ou --analyze (compte, capacités et gravité des jetons valides) | oui, trufflehog analyze (permissions et ressources accessibles) pour une partie des types d'identifiants | oui, --blast-radius pour les fournisseurs pris en charge (identités, permissions, ressources) |
| Révoque un secret | non documenté | non documenté en 1.9.0 (la révocation n'y apparaît que comme statut rendu par la validation) ; la version 2 en préversion annonce betterleaks revoke | non documenté | oui, kingfisher revoke, pour les fournisseurs pris en charge |
| Hook pre-commit | oui, hooks pre-commit fournis | oui, hooks pre-commit fournis | oui, documenté (hooksPath, framework pre-commit, Husky) | oui, script d'installation et framework pre-commit |
| Intégration CI | action gitleaks-action (dépôt séparé), image Docker | image Docker ghcr.io/betterleaks/betterleaks ; pas d'action dédiée dans le README | action GitHub trufflesecurity/trufflehog, image Docker | image Docker ghcr.io/mongodb/kingfisher ; pas d'action dédiée dans la documentation |
| Formats de sortie | JSON, CSV, JUnit, SARIF, modèle | JSON, CSV, JUnit, SARIF, modèle (JSONL pour validate) | texte, JSON, SARIF, format GitHub Actions | texte lisible, JSON, JSONL, BSON, TOON, SARIF, HTML |
| Licence | MIT | MIT | AGPL-3.0 | Apache-2.0 |
| Langage | Go | Go | Go | Rust |
Relevé effectué le 2026-10-30 sur la dernière version publiée de chaque outil. Les versions évoluent vite : vérifiez la date avant de vous fonder sur une cellule.
Le bon outil dépend d'abord de ce que vous voulez faire d'un secret une fois trouvé. Pour bloquer un commit ou une fusion, tous les quatre conviennent, et Gitleaks suffit quand les règles sont maîtrisées et qu'il est déjà en place. Pour distinguer les secrets vivants des restes d'exemples, il faut un outil qui vérifie : Betterleaks (sur option), TruffleHog ou Kingfisher. Pour savoir ce qu'un jeton actif ouvre, TruffleHog (analyze) et Kingfisher (--blast-radius) répondent, chacun sur les fournisseurs qu'ils prennent en charge ; Betterleaks ajoute une analyse comparable dans sa version 2, encore en préversion. Pour agir sans attendre le propriétaire du secret, seul Kingfisher documente une révocation depuis la ligne de commande dans les versions stables relevées ; Betterleaks en annonce une aussi pour sa version 2.
Si la cible dépasse le dépôt (tickets, messageries, images, buckets), regardez la ligne « Autres sources » : l'étendue varie beaucoup d'un outil à l'autre. Une licence AGPL-3.0 peut aussi peser dans le choix selon l'usage qu'en fait votre organisation. Enfin, un scanner qui ne trouve rien ne prouve rien : testez celui que vous retenez sur un dépôt contenant un faux secret connu avant de le brancher en CI. Pour figer l'existant et ne bloquer que les nouveautés, le guide detect-secrets traite une approche par baseline, et la comparaison des outils de détection de secrets élargit à d'autres candidats.
À retenir
Section intitulée « À retenir »- Kingfisher enchaîne cinq gestes dans un outil : détecter, valider, cartographier, trier, révoquer, avec une commande par geste.
- Seules la validation, la cartographie et la révocation quittent votre machine : ne les lancez que sur des comptes que vous avez le droit d'inspecter.
- Un secret se classe en actif, inactif, inconclusif ou présumé valide ; dans un script, testez
finding.validation.outcomeplutôt que le libellé affiché. - Le code de sortie distingue
200(résultat visible) de205(résultat validé), ce qui permet de ne bloquer que sur les secrets prouvés. --blast-radiuscartographie en lecture seule et au mieux : un accès absent du résultat n'est pas un accès impossible.kingfisher revokeest prudent et explicite ; il ne remplace ni la rotation ni l'audit des accès.- L'image se tire sans
v(2.16.0) et s'épingle par digest, en CI comme dans le hook pre-commit : les hooks fournis par le dépôt ne le sont pas. - Pour l'exigence SOCLE-SEC-GEN-6, un scan Kingfisher branché en CI ou en hook sur vos dépôts ne fournit que la première moitié de la preuve, le dispositif de détection. L'autre moitié est une procédure de réponse écrite : même si Kingfisher sait révoquer, c'est elle qui dit qui décide, quand lancer
kingfisher revokeet ce qui suit (rotation, audit, nettoyage de l'historique).
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de cette leçon est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : SAST : analyser le code source
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications