Secret scanning that goes one step further — it verifies whether a found credential is actually live by testing it against the provider. That single feature turns "hundreds of maybe-secrets" into "these three keys work right now, rotate them." You'll scan repos and history, filter to verified secrets, scan beyond Git (filesystem, S3, CI logs), gate CI, and run the leak response. Hands-on throughout.
The journey:
| You need | Why |
|---|---|
The trufflehog CLI |
Scan sources for secrets |
| A terminal | Everything starts on the CLI |
| A Git repo (and network) | Verification calls providers over the network |
Install with brew install trufflehog, the install script, or the Docker image. Confirm: trufflehog --version.
TruffleHog scans for secrets like other tools, but its detectors don't stop at "this looks like an AWS key." For each candidate, TruffleHog makes a harmless authenticated call to the provider (e.g. an AWS GetCallerIdentity) to check whether the credential still works. If it does, the finding is marked verified — a live, exploitable secret.
That flips triage from "eyeball hundreds of possible secrets" to "these specific credentials authenticate right now." It's the difference between a noisy scanner and an actionable one.
TruffleHog names the source as a subcommand:
# Scan a remote repo (full history)
trufflehog git https://github.com/org/project
# Scan a local repo
trufflehog git file://./my-repo
# Scan only commits since a point
trufflehog git file://. --since-commit HEAD~50
By default TruffleHog attempts verification on everything it finds. The output shows the detector (what kind of secret), whether it's verified, and where it was found (commit, file, line).
Cut straight to the credentials that matter:
# Only show secrets confirmed live against their provider
trufflehog git file://. --results=verified
# Show both, but you'll prioritise the verified ones
trufflehog git file://. --results=verified,unknown
Gate the pipeline hard on verified; track unverified as follow-up. This is what keeps secret scanning credible at scale — the gate only fires on real, working keys.
Secrets don't only live in Git. TruffleHog scans many source types with the same verification:
trufflehog filesystem /path/to/dir # local files
trufflehog docker --image myapp:latest # secrets baked into image layers
trufflehog s3 --bucket my-bucket # objects in an S3 bucket
trufflehog github --org my-org # every repo in an org
Scanning CI logs, S3 buckets, and image layers matters because credentials leak into places people forget — a debug log printed a token, a backup landed in a bucket, a key got copied into a Docker layer and "removed" later (but the layer remains).
For automation, emit JSON and process it:
trufflehog git file://. --json --results=verified > secrets.json
# Count verified findings by detector
jq -r 'select(.Verified==true) | .DetectorName' secrets.json | sort | uniq -c
Each result includes DetectorName, Verified, the raw match location, and SourceMetadata (commit, file, line). Wiring "count of verified findings" into a dashboard gives you a number that should trend toward zero.
Fail the build only on verified-live secrets to keep the gate low-noise:
# .github/workflows/trufflehog.yml
name: trufflehog
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history
- uses: trufflesecurity/trufflehog@main
with:
extra_args: --results=verified --fail
--fail returns a non-zero exit when a qualifying secret is found; scoping to --results=verified means the build breaks only on credentials that actually authenticate — so a red build is always real.
Run TruffleHog pre-commit to catch secrets before they're committed:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.63.0
hooks:
- id: trufflehog
args: ['git', 'file://.', '--since-commit', 'HEAD', '--fail']
When TruffleHog reports a verified secret, the response order is the same discipline as any leak:
A verified finding removes all ambiguity: you know the key works, so there's no debating whether to rotate.
Both find secrets in Git; they're often run together:
Common pattern: GitLeaks in the pre-commit hook for instant, offline blocking, and TruffleHog in CI / scheduled scans for verified findings and non-Git sources. Verification is TruffleHog's reason to exist — lean on it.
--results=verified so the pipeline breaks only on live credentials.fetch-depth: 0 in CI so history is fully covered.fetch-depth: 0, history secrets are missed.trufflehog git file://. and read the detector and verified status of a finding.--results=verified and compare the count to the unfiltered run.trufflehog filesystem on a directory containing a fake key file.--json and use jq to count verified findings by detector.Self-check:
You now have the loop: scan → verify → filter to live keys → scan beyond Git → gate CI on verified → rotate-first response. That's TruffleHog turning secret scanning into action.