Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Kingfisher : détecter, valider et révoquer un secret

Par mis à jour le

Améliorer cette page

Logo Kingfisher

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.

  • 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.

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.

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 cinq gestes de Kingfisher dans l'ordre : détecter avec kingfisher scan, valider auprès du fournisseur (résultat actif, inactif ou inconclusif), cartographier avec l'option --blast-radius, trier avec kingfisher view, puis révoquer avec kingfisher revoke. Une branche en pointillé indique que l'option --no-validate supprime tout appel au fournisseur.Détecterkingfisher scanValider :actif, inactif ou inconclusifCartographier :--blast-radiusTrier :kingfisher viewRévoquer :kingfisher revokeAucun appel au fournisseur :--no-validate
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

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.

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.

Fenêtre de terminal
# Homebrew (macOS, Linux)
brew install kingfisher
# Paquet PyPI qui fournit le binaire
uv tool install kingfisher-bin==2.16.0
# Image de conteneur : tag de version et digest
docker run --rm \
ghcr.io/mongodb/kingfisher:2.16.0@sha256:76ffeabd207296512359dccf740587e76f2dcd6821d3e53431a734627cb510aa \
--version

La commande affiche la version installée.

kingfisher 2.16.0

Les 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.

Fenêtre de terminal
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.json

Le 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.

Fenêtre de terminal
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.0

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.

Fenêtre de terminal
mkdir demo-kingfisher && cd demo-kingfisher
git init --quiet
cat > secret.yaml <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: ci-github
stringData:
token: ghp_R7kQ2mZ9xT4vB8nW1cL6yD3sF5hJ0aPeUgXi
EOF
git add secret.yaml
git -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.

Fenêtre de terminal
kingfisher scan . --format json --output findings.json
echo "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 : 200

Le 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.

Fenêtre de terminal
kingfisher view findings.json

Le 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 :

Fenêtre de terminal
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.

Fenêtre de terminal
cd .. && rm -rf demo-kingfisher

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 machineCe que cela prouve
Active Credentialverified_activeUn validateur a prouvé que le secret fonctionne : à traiter en premier.
Inactive Credentialverified_inactiveLe fournisseur a rejeté le secret : il est mort, mais reste à nettoyer.
Inconclusive ValidationunavailableLa vérification n'a pas abouti (délai, limite, erreur serveur) : ni preuve d'activité, ni d'inactivité.
Assumed Valid (Not Live-Validated)assumedLe secret est très probablement réel, mais personne ne l'a testé en direct.
Not Attemptednot_attemptedAucune 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.

Fenêtre de terminal
# Ne garder que les secrets prouvés actifs
kingfisher scan . --validation-filter active --format json

Quand 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.

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.

Fenêtre de terminal
kingfisher scan . --only-valid --blast-radius --format json --output findings.json

Le 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 Unauthorized

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.

Fenêtre de terminal
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: REVOKED
Status: 202
Response: {
}

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.

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.

CibleCommandeAuthentification
Dossier ou dépôt localkingfisher scan .aucune
Dépôt distantkingfisher scan https://github.com/org/depot.gitKF_GITHUB_TOKEN s'il est privé
Organisation GitHubkingfisher scan github --organization orgKF_GITHUB_TOKEN
Groupe GitLabkingfisher scan gitlab --group groupe --include-subgroupsKF_GITLAB_TOKEN
Image de conteneurkingfisher scan docker image:tagKF_DOCKER_TOKEN si le registre est privé
Bucket S3kingfisher scan s3 mon-bucket--profile ou KF_AWS_KEY et KF_AWS_SECRET
Tickets et wikiskingfisher scan jira et kingfisher scan confluenceKF_JIRA_TOKEN, KF_CONFLUENCE_TOKEN
Messageskingfisher 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.

Fenêtre de terminal
KF_GITHUB_TOKEN="$TOKEN_LECTURE" kingfisher scan github --organization mon-org --list-only

La 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.git
https://github.com/mon-org/infra-terraform.git
https://github.com/mon-org/site-vitrine.git

Compter 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.

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.

Les codes de sortie rendent Kingfisher utilisable en automatisation : ils distinguent un secret simplement trouvé d'un secret prouvé actif.

CodeSignification
0Aucun résultat visible.
200Des résultats visibles.
205Des résultats visibles et validés.
1Erreur fatale du scan.
2Arguments invalides.
3Rien à 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.

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: false

Installez 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éé.

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: secrets
on:
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 : 200

Si 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.

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ômeCause probableCorrection
manifest unknown en tirant l'imageTag écrit v2.16.0 avec un vUtiliser ghcr.io/mongodb/kingfisher:2.16.0, sans v.
Avec l'image, findings.json est introuvable, ou Permission deniedSans -u, le conteneur tourne avec l'utilisateur 10001 et écrit dans /app ; son /src monté n'est pas inscriptiblePasser -u "$(id -u):$(id -g)" et --output /src/findings.json.
kingfisher view dans le conteneur, rien dans le navigateurAucun port publié, ou serveur lié à 127.0.0.1 dans le conteneurAjouter -p 127.0.0.1:7890:7890 et --address 0.0.0.0.
Code de sortie 3Aucun 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 mortLe code compte les trouvailles avant le filtre, donc il reste 200 même quand le rapport est videAjouter --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 0Dé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ésFaire 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 ValidationFournisseur injoignable, délai ou limite de débitRelancer 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ègleRetirer --no-validate ; pour une règle sans validateur, vérifier à la main.
Erreur à la combinaison des options--only-valid et --validation-filter ensembleGarder une seule des deux.
Pipeline vert alors qu'un dépôt n'a pas été luScan partiel qui rend un code de succèsLire audit.summary.scan_partial dans le rapport JSON.
--since-commit ne trouve rien en CIClone peu profond sans le commit de baseCloner 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èreGitleaks 8.30.1Betterleaks 1.9.0TruffleHog 3.99.7Kingfisher 2.16.0
Dépôt Git et historiqueoui, gitleaks git (via git log -p)oui, betterleaks gitoui, trufflehog gitoui, historique inclus
Dépôt distant, organisationnon documenté (trois modes : git, dir, stdin)GitHub (organisation, utilisateur, PR, tickets, Actions, releases), GitLab (groupe, projet, merge requests), Hugging FaceGitHub (--org), GitLab, Hugging FaceGitHub, GitLab, Azure Repos, Bitbucket, Gitea, Hugging Face
Fichiers et répertoiresoui, gitleaks diroui, betterleaks diroui, trufflehog filesystemoui
Image de conteneurnon documenténon documentéoui, trufflehog dockeroui, kingfisher scan docker
Autres sourcesentrée standardentrée standard, S3 (dont Cloudflare R2)S3, GCS, Postman, Jenkins, Elasticsearch, CircleCI, Travis CI, syslog, entrée standardS3, GCS, Azure Blob Storage, Jira, Confluence, Slack, Teams, Postman
Vérifie qu'un secret est actifnon 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, erroroui, 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'impactnon 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'identifiantsoui, --blast-radius pour les fournisseurs pris en charge (identités, permissions, ressources)
Révoque un secretnon 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 revokenon documentéoui, kingfisher revoke, pour les fournisseurs pris en charge
Hook pre-commitoui, hooks pre-commit fournisoui, hooks pre-commit fournisoui, documenté (hooksPath, framework pre-commit, Husky)oui, script d'installation et framework pre-commit
Intégration CIaction gitleaks-action (dépôt séparé), image Dockerimage Docker ghcr.io/betterleaks/betterleaks ; pas d'action dédiée dans le READMEaction GitHub trufflesecurity/trufflehog, image Dockerimage Docker ghcr.io/mongodb/kingfisher ; pas d'action dédiée dans la documentation
Formats de sortieJSON, CSV, JUnit, SARIF, modèleJSON, CSV, JUnit, SARIF, modèle (JSONL pour validate)texte, JSON, SARIF, format GitHub Actionstexte lisible, JSON, JSONL, BSON, TOON, SARIF, HTML
LicenceMITMITAGPL-3.0Apache-2.0
LangageGoGoGoRust

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.


  • 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.outcome plutôt que le libellé affiché.
  • Le code de sortie distingue 200 (résultat visible) de 205 (résultat validé), ce qui permet de ne bloquer que sur les secrets prouvés.
  • --blast-radius cartographie en lecture seule et au mieux : un accès absent du résultat n'est pas un accès impossible.
  • kingfisher revoke est 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 revoke et ce qui suit (rotation, audit, nettoyage de l'historique).

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

6 questions
6 min.
70% requis

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

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn