Aller au contenu
Sécurité medium

Gitleaks : scanner vos dépôts Git pour détecter les secrets exposés

35 min de lecture

Logo Gitleaks

Gitleaks détecte les secrets exposés dans vos dépôts Git, fichiers et archives. Rapide et hautement configurable, c'est l'outil de référence pour les pre-commit hooks et les pipelines CI/CD. Avec plus de 150 règles intégrées, il identifie les clés AWS, tokens GitHub, Stripe, Slack et bien d'autres.

  • Comprendre comment Gitleaks détecte les secrets avec des règles regex
  • Scanner différentes sources : dépôts Git, fichiers, archives, entrée standard
  • Configurer des règles personnalisées et des exclusions
  • Intégrer Gitleaks dans vos pipelines CI/CD (GitHub Actions, GitLab CI)
  • Utiliser les fonctionnalités avancées : décodage, archives, baseline

Un secret poussé sur un dépôt public ne reste pas confidentiel le temps que vous vous en aperceviez. Des robots d'indexation surveillent en continu les évènements publics de GitHub et testent les identifiants trouvés, souvent avant même que l'auteur du commit ait fini sa journée. GitHub a d'ailleurs industrialisé la réponse avec le secret scanning et des partenariats de révocation automatique avec les fournisseurs cloud, ce qui en dit long sur la fréquence du phénomène.

Les secrets se retrouvent exposés pour plusieurs raisons :

SituationExempleRisque
Fichier de config commité.env oublié dans .gitignoreClés API en clair dans l'historique Git
Mot de passe hardcodépassword = "admin123" dans le codeAccès à la base de données
Token dans les logsAuthorization: Bearer sk_live_...Compromission de compte
Secret encodé en base64YXdzX3NlY3JldF9hY2Nlc3Nfa2V5...Fausse impression de sécurité
Historique GitSecret supprimé mais présent dans un ancien commitReste accessible via git log

Le problème : même si vous supprimez un secret, il reste dans l'historique Git. Et les scanners malveillants analysent tout l'historique, pas juste la branche principale.

Gitleaks utilise une approche basée sur des règles regex et des mots-clés pour détecter les secrets. Contrairement à d'autres outils, il ne vérifie pas si les secrets sont actifs, il se concentre sur la vitesse et la configurabilité.

L'étape de classification est celle qui détermine la qualité des résultats, et elle repose sur deux mécanismes empilés. Gitleaks commence par chercher des mots-clés peu coûteux à repérer (AKIA, sk_live_, ghp_), puis n'applique l'expression régulière complète qu'aux lignes qui ont passé ce premier filtre. C'est ce pré-filtrage qui explique la vitesse de l'outil, et c'est aussi pourquoi une règle personnalisée sans champ keywords ralentit sensiblement un gros dépôt.

  1. Découverte : Gitleaks parcourt les sources (Git, fichiers, archives, stdin)
  2. Classification : chaque ligne est comparée aux 150+ règles intégrées
  3. Rapport : les secrets trouvés sont affichés avec leur emplacement exact

Deux lignes de ce tableau sont des différenciateurs réels face aux autres scanners, les autres relèvent du confort. Le décodage automatique attrape les secrets encodés en base64 que la plupart des outils laissent passer, et le scan d'archives couvre le cas des artefacts de build livrés en .tar.gz où traînent des fichiers de configuration. En revanche, la configurabilité TOML a un revers : sans convention d'équipe, chaque dépôt finit avec son propre .gitleaks.toml et des allowlists qui divergent.

CaractéristiqueDétail
RapiditéÉcrit en Go, très performant
ConfigurabilitéRègles TOML personnalisables
DécodageBase64, hex, URL encoding (v8.26+)
ArchivesZIP, tar.gz, 7z... (v8.27+)
Règles compositesSecrets multi-parties (v8.28+)
IntégrationPre-commit, GitHub Actions, GitLab CI

La couverture est large sur les formats de jeton reconnaissables, c'est-à-dire ceux qui portent un préfixe fixe et une longueur constante. Elle est nettement plus faible sur les secrets sans forme identifiable : un mot de passe de base de données ou une clé interne maison ne seront détectés que par la règle générique generic-api-key, qui s'appuie sur l'entropie et génère beaucoup de faux positifs. C'est précisément pour ce cas qu'il faut écrire vos propres règles.

Gitleaks intègre plus de 150 règles pour détecter :

  • Cloud providers : AWS, GCP, Azure, DigitalOcean
  • Paiements : Stripe, PayPal, Square
  • Authentification : GitHub, GitLab, Slack, Discord
  • Bases de données : PostgreSQL, MySQL, MongoDB dans les URLs
  • Clés privées : RSA, DSA, ECDSA, OpenSSH
  • IA/ML : OpenAI, Anthropic, HuggingFace, Perplexity

Gitleaks est un binaire Go statique sans dépendance, ce qui rend les quatre méthodes ci-dessous équivalentes en résultat. Le critère de choix est la traçabilité : sur un poste de développement, un gestionnaire de versions comme asdf ou mise permet d'aligner toute l'équipe sur la même version. En CI, l'image de conteneur épinglée par digest est préférable, sinon un changement de version amont peut faire échouer un pipeline du jour au lendemain sur des règles nouvellement ajoutées.

Téléchargez le binaire depuis les releases GitHub. Le projet publie un fichier de sommes à côté de chaque archive : récupérez les deux et contrôlez l'empreinte avant d'extraire quoi que ce soit.

Fenêtre de terminal
VERSION="8.30.1"
BASE="https://github.com/gitleaks/gitleaks/releases/download/v${VERSION}"
# Archive + fichier de sommes publié par le projet
curl -fsSLO "${BASE}/gitleaks_${VERSION}_linux_x64.tar.gz"
curl -fsSLO "${BASE}/gitleaks_${VERSION}_checksums.txt"
# Contrôle de l'empreinte : doit afficher "... : OK"
sha256sum --check --ignore-missing gitleaks_${VERSION}_checksums.txt
# Extraire et installer seulement si le contrôle est passé
tar xzf gitleaks_${VERSION}_linux_x64.tar.gz gitleaks
sudo install -m 0755 gitleaks /usr/local/bin/gitleaks
# Vérification
gitleaks version
# 8.30.1

Depuis la version 8.19.0, Gitleaks utilise trois commandes principales : git, dir et stdin. Les anciennes commandes detect et protect sont dépréciées mais toujours fonctionnelles.

La commande git scanne l'historique complet d'un dépôt Git, y compris toutes les branches.

Fenêtre de terminal
# Scanner le dépôt dans le répertoire courant
gitleaks git
# Scanner un dépôt spécifique
gitleaks git /chemin/vers/mon-repo
# Afficher les détails (mode verbose)
gitleaks git -v
# Masquer la bannière
gitleaks git --no-banner

Exemple de sortie :

Finding: aws_access_key_id = AKIAIOSFODNN7EXAMPLE
Secret: AKIAIOSFODNN7EXAMPLE
RuleID: aws-access-token
Entropy: 3.646439
File: config.env
Line: 4
Commit: fbc14303ffbf8fb1c2c1914e8dda7d0121633aca
Author: dev@example.com
Date: 2024-06-16T17:17:40Z
Fingerprint: fbc14303ffbf8fb1c2c1914e8dda7d0121633aca:config.env:aws-access-token:4
Link: https://github.com/org/repo/blob/fbc14303.../config.env#L4

Cette sortie vous indique :

  • Le type de secret : aws-access-token
  • L'emplacement : fichier config.env, ligne 4
  • Le commit : hash, auteur, date
  • Le lien direct : vers la ligne sur GitHub/GitLab

--log-opts transmet sa valeur telle quelle à git log, sans validation par Gitleaks. Une option mal orthographiée fait donc échouer git, pas le scanner, et le message d'erreur remonté est celui de Git. C'est le levier principal pour rendre un scan supportable sur un dépôt ancien : limiter la plage divise le temps de scan d'autant, au prix d'un angle mort sur l'historique non couvert. Réservez cette réduction à la CI de pull request, et gardez un scan complet planifié à côté.

Fenêtre de terminal
# Scanner uniquement les 10 derniers commits
gitleaks git --log-opts="--max-count=10"
# Scanner une plage de commits
gitleaks git --log-opts="HEAD~20..HEAD"
# Scanner uniquement une branche spécifique
gitleaks git --log-opts="--all develop..main"

Ces deux options ne couvrent pas le même périmètre. --staged analyse ce qui se trouve dans l'index Git, c'est-à-dire exactement ce que le commit va enregistrer. --pre-commit s'appuie sur un git diff et sert au hook officiel du projet, qui combine d'ailleurs les deux. Point de vigilance : un secret déjà présent dans un commit antérieur ne sera vu par aucune des deux, seul gitleaks git sur l'historique complet le trouvera.

Fenêtre de terminal
# Scanner les fichiers stagés
gitleaks git --staged
# Scanner avec git diff (mode pre-commit)
gitleaks git --pre-commit

dir ignore complètement Git : pas d'historique, pas de commit, pas d'auteur dans le rapport, seulement le chemin et la ligne. C'est la commande à utiliser sur un artefact de build, un dossier de configuration exporté ou un répertoire extrait d'une image de conteneur. Deux comportements à connaître : le répertoire .git/ est exclu du parcours, mais les fichiers cachés et les fichiers listés dans .gitignore sont bien scannés, ce qui remonte souvent un .env local que gitleaks git ne verrait jamais. Les alias file et directory désignent la même commande.

Fenêtre de terminal
# Scanner un répertoire
gitleaks dir /chemin/vers/dossier
# Scanner un fichier spécifique
gitleaks dir config.env
# Scanner plusieurs chemins
gitleaks dir fichier1.log fichier2.env /etc/config/

stdin ouvre le scan à tout ce qui produit du texte, et c'est là que se trouvent les fuites que personne ne cherche : journaux applicatifs, sorties de kubectl describe, exports de variables d'environnement. Le rapport ne peut évidemment pas indiquer de fichier ni de commit, seulement le numéro de ligne dans le flux. Prudence en revanche sur la commande qui alimente le tube, kubectl logs sur un pod bavard peut envoyer plusieurs gigaoctets.

Fenêtre de terminal
# Scanner un fichier via pipe
cat config.env | gitleaks stdin
# Scanner la sortie d'une commande
kubectl logs deployment/mon-app | gitleaks stdin
# Scanner un fichier décompressé à la volée
gunzip -c logs.gz | gitleaks stdin

Les quatre fonctions qui suivent servent des besoins différents mais partagent une logique : elles élargissent ou restreignent le périmètre du scan. Le décodage et le scan d'archives font apparaître des secrets invisibles à un scan naïf, la baseline et les formats de sortie servent à rendre les résultats exploitables au quotidien sans noyer les équipes sous les alertes déjà connues.

Gitleaks peut décoder automatiquement les secrets encodés en base64, hexadécimal ou URL encoding. Par défaut, le décodage est activé avec une profondeur de 5.

Fenêtre de terminal
# Activer le décodage récursif (profondeur 2)
gitleaks dir /chemin --max-decode-depth=2
# Désactiver le décodage
gitleaks dir /chemin --max-decode-depth=0

Exemple : un token Stripe encodé en base64 sera détecté :

# Fichier contenant : c2tfbGl2ZV80ZUMzOUhxTHlqV0Rhcmp0VDF6ZHA3ZGMK
Finding: sk_live_4eC39HqLyjWDarjtT1zdp7dc
Secret: sk_live_4eC39HqLyjWDarjtT1zdp7dc
RuleID: stripe-access-token
Tags: [decoded:base64 decode-depth:1]

Les tags decoded:base64 et decode-depth:1 indiquent que le secret a été trouvé après décodage.

Le scan d'archives est désactivé par défaut (--max-archive-depth vaut 0), ce qui surprend beaucoup d'utilisateurs qui croient leurs .tar.gz couverts. Il faut l'activer explicitement. Montez la profondeur avec parcimonie : chaque niveau supplémentaire signifie une extraction sur disque, et une archive piégée contenant des milliers de fichiers imbriqués transforme le scan en saturation de l'espace temporaire du runner.

Fenêtre de terminal
# Scanner une archive avec profondeur 1
gitleaks dir archive.tar.gz --max-archive-depth=1
# Scanner des archives imbriquées (profondeur 3)
gitleaks dir archives/ --max-archive-depth=3

Formats supportés : zip, tar, tar.gz, tar.bz2, tar.xz, 7z, rar, et plus.

Le chemin dans les résultats indique l'emplacement dans l'archive :

File: nested.tar.gz!inner/files.tar!config/.env

Cela signifie : .env est dans files.tar, qui est dans nested.tar.gz.

La baseline permet d'ignorer les secrets déjà identifiés lors de scans ultérieurs. Utile pour les projets avec un historique contenant des secrets déjà traités.

  1. Créer la baseline en générant un rapport initial

    Fenêtre de terminal
    gitleaks git --report-path baseline.json
  2. Utiliser la baseline pour les scans suivants

    Fenêtre de terminal
    gitleaks git --baseline-path baseline.json --report-path findings.json

    Seuls les nouveaux secrets seront rapportés.

Le choix du format dépend de qui lit le rapport. SARIF est le seul qui s'intègre nativement aux tableaux de bord de sécurité GitHub et GitLab, JUnit fait apparaître les fuites comme des tests en échec dans l'interface de la plupart des CI, et JSON est le format à conserver puisque c'est lui qui contient les fingerprint réutilisables dans un .gitleaksignore. Le format template reste réservé aux rapports internes qui doivent respecter un gabarit maison.

Fenêtre de terminal
# JSON (défaut si --report-path est utilisé)
gitleaks git -f json -r report.json
# CSV
gitleaks git -f csv -r report.csv
# SARIF (pour GitHub Code Scanning)
gitleaks git -f sarif -r report.sarif
# JUnit (pour CI/CD)
gitleaks git -f junit -r report.xml
# Template personnalisé
gitleaks git -f template --report-template custom.tmpl -r report.txt
# Sortie JSON vers stdout
gitleaks git -f json -r -

Gitleaks se configure par un fichier .gitleaks.toml versionné avec le code. Deux erreurs coûtent cher ici. La première consiste à écrire une configuration sans useDefault = true, ce qui désactive silencieusement les 150 règles intégrées. La seconde consiste à empiler des exclusions jusqu'à ce que le scan ne renvoie plus rien, ce qui donne un pipeline vert et aucune sécurité. Traitez ce fichier comme du code de production : revue obligatoire, et une justification écrite pour chaque exclusion.

Cet ordre explique la panne la plus fréquente en CI : un .gitleaks.toml correctement écrit mais ignoré, parce qu'une variable GITLEAKS_CONFIG traîne dans l'environnement du runner et prend le dessus. Notez aussi le point 4, le fichier est cherché dans le répertoire scanné, pas dans le répertoire courant. Scanner /opt/app depuis votre $HOME ne charge donc pas le .gitleaks.toml de votre $HOME. En cas de doute, --log-level=debug indique la configuration réellement retenue.

  1. Option --config ou -c
  2. Variable d'environnement GITLEAKS_CONFIG (chemin fichier)
  3. Variable d'environnement GITLEAKS_CONFIG_TOML (contenu TOML)
  4. Fichier .gitleaks.toml dans le répertoire scanné

Si aucune configuration n'est trouvée, Gitleaks utilise les règles par défaut.

Le réflexe à prendre est useDefault = true. Sans cette ligne, votre fichier remplace entièrement le jeu de règles intégré au lieu de le compléter, et vous vous retrouvez avec un scanner qui ne cherche plus que vos propres motifs. disabledRules sert ensuite à retirer chirurgicalement une règle trop bruyante, generic-api-key étant de loin la première candidate. Désactivez-la seulement après avoir écrit vos règles maison, sinon vous perdez la seule détection qui couvre les secrets sans format connu.

.gitleaks.toml
# Titre de la configuration
title = "Configuration personnalisée"
# Étendre la configuration par défaut
[extend]
useDefault = true
# Désactiver certaines règles par défaut
disabledRules = ["generic-api-key"]

Deux champs conditionnent le résultat. keywords n'est pas décoratif : c'est le pré-filtre qui évite d'appliquer la regex à chaque ligne du dépôt, et l'oublier peut multiplier le temps de scan. entropy fixe un seuil de désordre en dessous duquel la correspondance est rejetée, ce qui écarte les valeurs de test du type int_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa. Enfin, la regex suit la syntaxe RE2 de Go, qui ne connaît ni les groupes arrière ni le lookahead : une expression copiée depuis PCRE peut être refusée au chargement.

.gitleaks.toml
[[rules]]
# Identifiant unique
id = "internal-api-key"
# Description
description = "Clé API interne de l'entreprise"
# Expression régulière (syntaxe Go)
regex = '''int_[a-zA-Z0-9]{32}'''
# Mots-clés pour pré-filtrage (optimisation)
keywords = ["int_", "internal_api"]
# Entropie minimum (optionnel)
entropy = 3.5
# Tags pour le reporting
tags = ["internal", "api-key"]

Une allowlist est un risque assumé, pas un correctif : tout ce qu'elle couvre cesse d'être vérifié, y compris les vrais secrets qui atterriraient plus tard au même endroit. Préférez donc les critères les plus étroits possibles. Exclure tests/ en bloc est commode mais large ; cibler un fichier de fixtures précis ou un motif de valeur connue, via regexes et stopwords, laisse le reste du répertoire sous surveillance. Documentez chaque entrée avec description, c'est ce champ qu'on relit six mois plus tard en se demandant pourquoi une règle est muette.

.gitleaks.toml
# Allowlist globale (s'applique à toutes les règles)
[[allowlists]]
description = "Fichiers de test et documentation"
paths = [
'''tests/''',
'''fixtures/''',
'''\.md$''',
]
# Allowlist pour une règle spécifique
[[rules]]
id = "aws-access-token"
[[rules.allowlists]]
description = "Clés de test AWS"
regexes = ['''AKIAIOSFODNN7EXAMPLE''']
stopwords = ["example", "test", "demo"]

targetRules résout un problème concret : avant la v8.25, exclure un même répertoire de test pour dix règles imposait de dupliquer dix blocs d'allowlist, avec la dérive qui s'ensuit quand on en oublie un. La portée reste explicite, seules les règles nommées sont concernées, ce qui évite l'effet de bord d'une allowlist globale qui aveugle aussi les règles ajoutées plus tard.

.gitleaks.toml
[[allowlists]]
# Appliquer à des règles spécifiques
targetRules = ["aws-access-token", "generic-api-key"]
description = "Fichiers de test"
paths = ['''tests/.*\.json$''']

Les règles composites répondent au cas où une seule moitié du secret n'a aucune valeur. Un identifiant AWS AKIA... seul ne permet rien ; associé à sa clé secrète située quelques lignes plus bas, il donne un accès complet. Le paramètre withinLines définit la fenêtre de proximité acceptée. Un effet secondaire bienvenu : en exigeant les deux parties, ce type de règle réduit fortement les faux positifs sur les identifiants publics cités dans la documentation.

.gitleaks.toml
[[rules]]
id = "aws-keypair"
description = "Paire clé/secret AWS"
regex = '''AKIA[0-9A-Z]{16}'''
# Règle requise : le secret doit être proche
[[rules.required]]
id = "aws-secret-pattern"
withinLines = 5 # Le secret doit être dans les 5 lignes suivantes

Cette annotation vit dans le code, ce qui la rend visible en revue de code, contrairement à une allowlist enfouie dans un fichier de configuration. C'est son principal intérêt. Son principal danger aussi : n'importe qui peut la coller sur une vraie fuite pour faire passer un pipeline. Sur un dépôt sensible, l'option --ignore-gitleaks-allow permet de lancer un scan d'audit qui neutralise toutes ces annotations et révèle ce qu'elles masquent.

# Cette clé est un exemple pour la documentation
AWS_KEY = "AKIAIOSFODNN7EXAMPLE" # gitleaks:allow

Le fingerprint combine le commit, le fichier, l'identifiant de règle et le numéro de ligne. Cette précision est une qualité, chaque exception est chirurgicale, mais aussi une fragilité : réécrire l'historique ou déplacer la ligne change l'empreinte, et l'exception cesse silencieusement de s'appliquer. Récupérez toujours ces valeurs depuis un rapport JSON plutôt que de les composer à la main, et rappelez-vous qu'une entrée ici ne dispense jamais de révoquer le secret concerné.

.gitleaksignore
# Format : fingerprint (depuis le rapport JSON)
fbc14303ffbf8fb1c2c1914e8dda7d0121633aca:config.env:aws-access-token:4
77b2a3e56973785a52ba4ae4b8dac61d4bac016f:keys:private-key:6

Les trois intégrations ci-dessous ne se remplacent pas, elles se complètent. Le hook pre-commit est rapide et local mais contournable d'un --no-verify, la CI est incontournable mais n'agit qu'après le push. Une chaîne saine combine les deux : le hook pour le confort du développeur, la CI pour la garantie.

Bloquez les secrets avant qu'ils ne soient commités. Le dépôt Gitleaks publie trois identifiants de hook : gitleaks compile le binaire en Go, gitleaks-docker passe par l'image de conteneur, gitleaks-system réutilise le binaire déjà installé sur le poste. Le premier est le plus simple, le troisième le plus rapide si votre équipe gère déjà la version via asdf ou mise.

.pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
  1. Installer pre-commit

    Fenêtre de terminal
    pip install pre-commit
  2. Créer le fichier de configuration

    Fenêtre de terminal
    cat > .pre-commit-config.yaml << 'EOF'
    repos:
    - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
    - id: gitleaks
    EOF
  3. Installer les hooks

    Fenêtre de terminal
    pre-commit install
  4. Tester

    Fenêtre de terminal
    git add . && git commit -m "test"
    # Si un secret est détecté, le commit sera bloqué

Pour désactiver temporairement le hook :

Fenêtre de terminal
SKIP=gitleaks git commit -m "skip check"

Utilisez l'action officielle Gitleaks. Trois points de ce workflow méritent votre attention. Le fetch-depth: 0 est obligatoire : sans lui, le checkout ne récupère qu'un commit et le scan d'historique ne voit rien. Les actions sont épinglées par SHA plutôt que par tag, car un tag Git peut être redéplacé vers un autre commit par le mainteneur ou un attaquant qui aurait pris la main sur le dépôt. Enfin, permissions: {} au niveau du workflow retire tous les droits par défaut, et chaque job ne récupère que ce dont il a besoin : contents: read pour cloner, pull-requests: write parce que l'action commente les pull requests.

.github/workflows/gitleaks.yml
name: Gitleaks
on:
push:
branches: [main]
pull_request:
permissions: {}
jobs:
gitleaks:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # Important : récupérer tout l'historique
persist-credentials: false
- uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Uniquement pour les dépôts appartenant à une organisation
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}

persist-credentials: false empêche actions/checkout de laisser le jeton d'authentification dans le fichier .git/config du runner, où n'importe quelle étape ultérieure du job pourrait le relire.

Intégrez Gitleaks dans vos merge requests. Deux détails conditionnent le bon fonctionnement du job. D'abord, le chemin à scanner est un argument positionnel de la commande git, pas une option : l'ancien indicateur --source a disparu et renvoie désormais unknown flag. Ensuite, GIT_DEPTH: 0 est indispensable, car GitLab clone par défaut en profondeur limitée et un scan d'historique sur un clone tronqué ne prouve rien.

.gitlab-ci.yml
stages:
- security
gitleaks:
stage: security
image: ghcr.io/gitleaks/gitleaks:v8.30.1@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f
variables:
GIT_DEPTH: 0 # historique complet, sinon le scan est aveugle
script:
- gitleaks git "$CI_PROJECT_DIR" --verbose
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
allow_failure: false

Le code de sortie vaut 1 par défaut lorsqu'une fuite est trouvée, donc --exit-code n'est utile que pour changer cette valeur. Combiné à allow_failure: false, le pipeline s'arrête bien sur détection.

Pour générer un rapport SARIF compatible avec GitLab Security Dashboard, ajoutez le format de rapport et déclarez l'artefact. Conservez la clé paths en plus de reports : sans elle, le fichier n'est pas téléchargeable depuis l'interface, ce qui complique l'analyse quand le tableau de bord n'est pas disponible sur votre édition de GitLab.

.gitlab-ci.yml
gitleaks:
stage: security
image: ghcr.io/gitleaks/gitleaks:v8.30.1@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f
variables:
GIT_DEPTH: 0
script:
- gitleaks git "$CI_PROJECT_DIR" -f sarif -r gl-sast-report.sarif
artifacts:
reports:
sast: gl-sast-report.sarif
paths:
- gl-sast-report.sarif

Un point avant de lire ce tableau : « aucun résultat » n'est pas une bonne nouvelle en soi. Avant de conclure qu'un dépôt est propre, vérifiez que le scan a bien vu quelque chose, la ligne scanned ~N bytes de la sortie doit afficher un volume cohérent avec la taille du dépôt. Un 0 bytes signale presque toujours un clone tronqué en CI ou un chemin de départ erroné, pas l'absence de secrets.

SymptômeCause probableSolution
Aucun résultatPas de secret trouvéNormal si le repo est propre
Faux positifs nombreuxSecrets de test, exemplesUtiliser .gitleaksignore ou allowlists
Scan très lentHistorique Git volumineuxUtiliser --log-opts="--max-count=100"
Erreur "no such file"URL distante non supportéeCloner le repo localement d'abord
Secret encodé non détectéDécodage désactivéVérifier --max-decode-depth
Archive non scannéeScan d'archives désactivéActiver --max-archive-depth=1

Le niveau debug répond à la question la plus utile en cas de comportement inattendu : quelle configuration a été chargée et quelles règles sont actives. Le niveau trace descend jusqu'au détail de chaque correspondance testée et sature vite un terminal ; réservez-le à l'analyse d'une règle personnalisée qui ne déclenche pas, en redirigeant la sortie vers un fichier.

Fenêtre de terminal
# Niveau debug
gitleaks git --log-level=debug
# Niveau trace (très verbeux)
gitleaks git --log-level=trace

Un scan qui traîne est presque toujours dû à quelques fichiers précis, pas à une lenteur générale : archives volumineuses, fichiers minifiés d'une seule ligne, jeux de données commités par erreur. Depuis la v8.26, Gitleaks les signale dans les journaux de débogage, ce qui permet de traiter la cause plutôt que d'abaisser la couverture du scan.

Fenêtre de terminal
gitleaks git --log-level=debug 2>&1 | grep "slow"

Ajoutez ces fichiers à une allowlist ou utilisez --max-target-megabytes :

Fenêtre de terminal
# Ignorer les fichiers > 10 MB
gitleaks git --max-target-megabytes=10

Détecter un secret coûte toujours plus cher que l'empêcher d'exister. Les trois volets ci-dessous suivent donc cet ordre de valeur : prévention d'abord, détection ensuite, remédiation en dernier recours parce qu'à ce stade le secret est déjà compromis.

Prévention : empêcher les secrets d'arriver dans Git

Section intitulée « Prévention : empêcher les secrets d'arriver dans Git »

Ces quatre mesures se renforcent mutuellement, mais une seule change vraiment la donne : le gestionnaire de secrets. Tant qu'un secret existe sous forme de chaîne dans un fichier du poste de développement, il finira par être commité par accident. Les trois autres mesures réduisent la probabilité, la quatrième supprime la cause.

  1. Pre-commit hooks : bloquer les commits contenant des secrets
  2. Fichiers .gitignore : exclure .env, *.pem, credentials.json
  3. Gestionnaire de secrets : utiliser OpenBao, Vault, AWS Secrets Manager ou Passbolt
  4. Variables d'environnement : injecter les secrets au runtime

Le scan de pull request et le scan périodique ne cherchent pas la même chose. Le premier porte sur un différentiel et doit rester rapide pour ne pas ralentir les équipes. Le second repasse sur l'historique complet et rattrape ce que les règles d'hier ne savaient pas détecter : chaque montée de version de Gitleaks ajoute des règles, donc un dépôt déclaré propre l'an dernier ne l'est pas forcément aujourd'hui.

  1. CI/CD : scanner chaque pull request et chaque push
  2. Scans périodiques : auditer l'organisation complète chaque semaine
  3. Nouveaux dépôts : ajouter Gitleaks dès la création

L'ordre de cette liste est un ordre de priorité, pas une suite d'options. La rotation passe avant tout le reste, y compris avant le nettoyage de l'historique : tant que le secret reste valide, réécrire les commits ne protège de rien puisque des clones ont pu être faits entre-temps. Pour l'étape 3, git filter-branch est déprécié par le projet Git lui-même au profit de git-filter-repo, plus rapide et moins piégeux ; BFG Repo-Cleaner reste une alternative valable.

  1. Rotation immédiate : révoquer et recréer le secret exposé
  2. Audit des accès : vérifier les journaux d'utilisation du secret compromis
  3. Nettoyage de l'historique : utiliser git filter-repo ou BFG Repo-Cleaner
  4. Post-mortem : comprendre comment le secret a été exposé

Gitleaks et TruffleHog sont les deux outils open source les plus populaires pour la détection de secrets :

CritèreGitleaksTruffleHog
Vitesse✅ Très rapide⚠️ Plus lent (vérification)
Vérification automatique❌ Non✅ Oui (800+ APIs)
Sources supportées3 (Git, dir, stdin)18 (Git, Docker, S3, Jenkins...)
Nombre de règles150+800+
ConfigurationTOML flexibleYAML simple
Décodage✅ Base64, hex, URL✅ Base64, UTF-16
Archives✅ ZIP, tar...✅ via --archive-max-depth
Règles composites✅ (v8.28+)❌ Non

Recommandation :

  • Gitleaks : idéal pour les hooks pre-commit et les scans CI/CD rapides
  • TruffleHog : préférable pour les audits de sécurité avec vérification des secrets actifs

Une précision sur les deux dernières lignes du tableau, car les deux projets évoluent vite : TruffleHog dispose lui aussi de décodeurs (base64, UTF-16, échappements) et sait descendre dans les archives via ses options --archive-max-depth et --archive-max-size. Le vrai différenciateur reste ailleurs : Gitleaks privilégie la vitesse et le contrôle fin des règles, TruffleHog la vérification active des identifiants trouvés auprès des API concernées.

Vous pouvez utiliser les deux : Gitleaks en pre-commit pour la rapidité, TruffleHog en scan périodique pour la vérification.


  1. Trois commandes : git (historique), dir (fichiers), stdin (pipeline)
  2. 150+ règles intégrées : AWS, Stripe, GitHub, Slack, et bien plus
  3. Décodage automatique : base64, hex et URL encoding, actif par défaut à la profondeur 5
  4. Scan d'archives : désactivé par défaut, à activer avec --max-archive-depth
  5. Baseline : ignorer les secrets déjà traités
  6. Pre-commit : bloquer les secrets avant qu'ils n'atteignent Git
  7. Rotation immédiate : un secret exposé est un secret compromis
  8. En CI : action épinglée par SHA, permissions: {}, historique complet, image épinglée par digest

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn