Git, CI/CD & GitOpsXXXV · Secrets in GitDetection
Detection with secret scanning — gitleaks, truffleHog, and the CI gate
What you'll learn
- Run gitleaks detect against a repository and interpret the report
- Distinguish regex-based detection from entropy-based detection and the false-positive cost of each
- Wire a secret-scanning step into a CI pipeline as a merge gate
- Recognise the position trade-off between pre-commit hooks, pre-receive hooks, and CI gates
Prerequisites
Practice
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Detection is the only preventive measure that catches a secret before it is committed, and the only detective measure that catches one after the leak. The lesson is the detector landscape: gitleaks, TruffleHog, the native GitHub and GitLab scanners, and the gate that turns a report into a control.
The detector landscape
- gitleaks ships with hundreds of regex rules for known providers (AWS, GitHub, Stripe, OpenAI) and falls back to Shannon entropy for unknown high-entropy strings. Fast enough for a pre-commit hook, strict enough for a CI gate.
gitleaks detect --source . --verbose
gitleaks protect --staged --verbose
- TruffleHog focuses on high-entropy strings and verifies them against the live provider. The difference between “matched a regex” and “verified live” is the difference between a queue of alerts and a queue of confirmed incidents.
- GitHub native secret scanning runs on every push and partners with major providers; in some cases it auto-revokes the credential.
- GitLab native secret detection runs as a pipeline stage with a broad default ruleset.
Production teams typically run gitleaks in CI as the gate, TruffleHog on a nightly schedule, and the native scanner for partner-token coverage.
flowchart LR
A["commit attempt"] --> B["pre-commit: gitleaks protect"]
B -->|"clean"| C["push"]
B -->|"finding"| Z["block commit"]
C --> D["CI: gitleaks detect"]
D -->|"clean"| E["merge"]
D -->|"finding"| Y["fail build"]
E --> F["nightly: TruffleHog history"]
The CI gate
The shape in GitHub Actions:
name: secret-scan
on:
pull_request:
branches: [main]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${ secrets.GITHUB_TOKEN }
The step fails the build when gitleaks finds a secret; the failed build locks the merge; the engineer is forced to remove the secret or escalate. The override requires a senior reviewer’s approval and is logged in the audit trail.
Regex and entropy trade-off
Regex rules match a known provider’s credential format. False-positive rate is low; false-negative rate is high because the unknown credential is not in the ruleset.
Entropy rules flag any string of sufficient length and randomness. False-positive rate is high because base64 blobs look like secrets; false- negative rate is low because unknown credentials are flagged.
The production trade-off is both, with careful tuning. gitleaks’s default ruleset is the starting point: regex for known providers, entropy with a high threshold (Shannon entropy greater than 4.5) for unknown. The cost of false positives is review fatigue; the cost of false negatives is a leaked secret.
The position of the gate
Three positions exist; the production answer is all three:
- Pre-commit (engineer’s machine). Runs
gitleaks protect --stagedbefore the commit. Fastest catch; skippable with--no-verify. - Pre-receive (forge or mirror). Runs on every push. Cheapest catch; needs forge support.
- CI (pipeline). Runs on every pull request. Most visible catch; the commit lands on the branch before the gate runs.
The three are layered. The pre-commit hook catches the secret the engineer did not realise was a secret; the pre-receive hook catches the push that bypassed the local hook; the CI gate catches the push that bypassed both; the nightly full-history scan catches the historical commits that were scanned before the ruleset was complete.
Production discipline
- The gate is the merge, not the alert. A detector that prints a report and lets the merge proceed is a reporting tool. The gateway is the build that fails; the merge that is blocked.
- The ruleset is owned. The team owns the ruleset for the credentials the team issues; the ruleset changes when the credentials change.
- Verification is the difference between a queue and a backlog. A regex match is a candidate. A verified credential is an incident.
Cross-course references
- Linux for Production Sysadmins - Part XXXIV (ConfigMgmt) covers the rotation that runs after a verified finding.
- Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers the allowlist for vault content.
- Terraform for Production Sysadmins - Parts
IX-XII (State) cover committed
.tffiles and variable files the detector must scan.
Quiz
Knowledge check · 4 questions
Q1. Which control is the merge gate for secret scanning?
Q2. A regex-only ruleset is not sufficient for a production repository because it has a low false-positive rate.
Q3. Name the three positions where a secret-scanning gate can run, and explain why production runs all three.
Q4. A team enables gitleaks in CI and expects the problem solved. Three months later, a secret is leaked. Diagnose the failure.
The team configured gitleaks as a CI step on pull requests to main. An engineer commits an AWS access key to a feature branch, then opens a pull request. The CI step fails, the engineer sees the failure, deletes the file, commits again, and the merge proceeds. Three months later, the AWS access key appears in a public S3 bucket's logs. The team's forensics shows the original commit was scanned but the workaround was not logged.
Passing score: 75%. Answers are checked in this browser.