Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXXV · Secrets in GitDetection

Detection with secret scanning — gitleaks, truffleHog, and the CI gate

Advanced⏱ ~24 min🧪 Lab requiredgitgitleaks

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

Not yet marked complete on this device.

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 --staged before 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

  1. 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.
  2. The ruleset is owned. The team owns the ruleset for the credentials the team issues; the ruleset changes when the credentials change.
  3. 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 .tf files and variable files the detector must scan.

Quiz

Knowledge check · 4 questions

  1. Q1. Which control is the merge gate for secret scanning?

  2. Q2. A regex-only ruleset is not sufficient for a production repository because it has a low false-positive rate.

  3. Q3. Name the three positions where a secret-scanning gate can run, and explain why production runs all three.

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