Tools Used in DevSecOps · TruffleHog

TruffleHog

TruffleHog is the open-source secrets-detection tool the CDP (Certified DevSecOps Professional) curriculum names directly, and its headline feature is why: for a large share of the credential types it recognizes, TruffleHog doesn't stop at "this string looks like a secret." It takes the matched value and fires a live, read-only API call at the real provider that would have issued it — AWS, GitHub, Stripe, Slack, and hundreds more — and reports back whether that credential is actually still active right now. Every other scanner on this course's list, gitleaks included, stops at pattern and entropy. TruffleHog adds a fact-check on top, and that single design choice is what this whole page is about.

☺ Explain it like I'm 10

Imagine two ways to check whether a key someone found actually opens a specific door. One way: look at the key and guess from its shape whether it's probably a house key — right size, right cut, probably real. The other way: walk up to the door and actually try it in the lock. TruffleHog is the second approach. For most credential types it knows about, it doesn't just decide a string "looks like" a real AWS key or GitHub token — it tries the key in the lock, safely and without breaking anything (a read-only call like "who am I logged in as"), and tells you, with certainty, whether that door opens right now.

🐘Your host for this topic: Ellie the Elephant — Ellie doesn't just notice a credential lying around where it shouldn't be. Before she decides how alarmed to be, she checks whether it still opens anything.

What TruffleHog is, and the problem it solves

☺ Like you're 10: Old secret-scanners could only guess. This one actually checks — and that turns a pile of maybes into a short, certain list.

TruffleHog started in 2016 as a much simpler tool: a Python script by Dylan Ayrey that walked git history looking for high-Shannon-entropy strings — the observation that a real API key or private key, being close to random, has a statistically higher "surprise per character" than ordinary source code or prose. That first version was useful and also noisy, because entropy alone can't distinguish a real secret from a hash, a UUID, a minified bundle, or any other high-randomness string that happens to live in a repository. TruffleHog v3 — a full rewrite in Go by Truffle Security Co., and the version actually in production use today — is a different tool wearing the same name. It replaced entropy-only guessing with several hundred purpose-built detectors, one per credential type or vendor format, and it added the feature this page is really about: live verification. Truffle Security's own detector count keeps climbing with every release, comfortably past 800 as of recent versions — treat any specific number here as a snapshot, and check the project's own repository for the current count rather than something fixed.

The problem this solves is specifically the one every regex- or entropy-based scanner leaves open. gitleaks, Semgrep's secret-shaped rules, and detect-secrets can all tell you a string looks like a live AWS access key. None of them can tell you whether that key still works — whether it was rotated eighteen months ago, whether it's a deliberately fake value sitting in a test fixture, or whether it's a real, currently-exploitable credential sitting in a commit from last week. Every hit from a pattern-only scanner is a "maybe," and a team that spends months triaging maybes eventually starts skimming past all of them — the same alert-fatigue failure this course keeps returning to for every gate that cries wolf too often. TruffleHog's verification step collapses that maybe into a fact: Verified means a real, currently-active credential is sitting in your repository right now; Unverified means the pattern matched but nothing confirmed it either way. See Static Analysis & Secrets Detection for where this fits next to SAST triage generally — that page treats TruffleHog's verified/unverified split as the central distinction of its own secrets-detection chapter.

◆ Key idea

Verification only exists for the detector types where a safe, side-effect-free check is possible — reading identity or account info, never spending money, deleting data, or sending a message. TruffleHog is willing to tell a provider "prove you're valid" on your behalf; it will not use a found credential to actually do anything with it. That boundary is exactly why the feature is trustworthy enough to run unattended in a pipeline.

The pipeline: sources, chunkers, decoders, detectors, verifiers

☺ Like you're 10: Every scan is the same five-step assembly line, no matter whether it's reading a git repo, a container image, or an S3 bucket.

TruffleHog v3's engine is a concurrent producer/consumer pipeline, and the vocabulary matters because each stage maps to a real CLI subcommand or config block. Understanding it is most of what makes an unfamiliar flag combination make sense on first read.

Source git · github s3 · docker filesystem Chunker splits bytes into scannable pieces Decoder unwraps Base64 and similar encodings Detector keyword pre-filter + vendor regex ~800 detectors, one per credential type Verifier live, read-only API call — sts:GetCallerIdentity, GitHub /user, Stripe balance... only where one exists Result classification Verified confirmed active Unverified matched, unconfirmed Error / unknown couldn't reach provider Every hit carries SourceMetadata too: repository, commit, file, line, and — for git sources — the committing email.

Named individually: Sources are where TruffleHog reads bytes from — not just "a git repo." Dedicated source connectors exist for local and remote git repositories (full history, every branch, by default), whole GitHub or GitLab organizations, plain filesystem paths, S3 and GCS buckets, Docker images (scanned layer by layer, not just the final flattened filesystem), and CI build-log sources like CircleCI, Travis, and Jenkins, among others — each is its own subcommand. Chunkers split whatever a source returns into bounded, scannable pieces, since a source can be a single commit diff or a multi-gigabyte image layer. Decoders unwrap common encodings — Base64 chief among them — before detection runs, because a Base64-encoded key is invisible to a regex scanning raw bytes. Detectors are the roughly 800 purpose-built matchers, each combining a small set of trigger keywords (a cheap pre-filter — skip a chunk entirely if none of a detector's keywords appear, which is most of what keeps a full-history scan tractable) with a regex specific to that vendor's credential format. And verifiers, where a detector implements one, take a matched value and fire the live, read-only call that turns a match into a confirmed fact.

Detectors and what "Verified" actually means

☺ Like you're 10: The check is different for every kind of key, but the idea is always the same — ask the real service a harmless question only a working key could answer.

Each verifier is written specifically for its provider's API, and the pattern repeats: find the cheapest possible read-only endpoint that requires authentication and returns a clean success/failure signal. A few concrete examples make the shape obvious:

Contrast that with what gitleaks does with the exact same matched string: nothing further. gitleaks is regex and entropy scoring over a diff or a full history, with zero network calls of any kind — which is precisely why it's fast, safe to run fully offline, and the right default for a pre-commit hook. It's also exactly why every one of its hits is unconfirmed. Truffle Security's own published benchmarks put the false-positive reduction from verification in the 90%-plus range for the detector types it covers — treat that figure as vendor-sourced marketing rather than an independently audited number, but the direction is not in dispute: in any repository old enough to have accumulated rotated credentials, revoked tokens, and obviously-fake test fixtures, the overwhelming majority of pattern-only hits turn out to be dead on inspection, and verification is what tells you which handful aren't without a human tracing each one down.

Custom detectors: teaching TruffleHog your own token format

☺ Like you're 10: The built-in detectors know every major vendor's key shape already — a config file is how you teach it your own company's shape too.

The ~800 built-in detectors ship compiled into the binary, so a default run needs no rule file at all — a real difference from gitleaks, which always needs a TOML ruleset (even if it's the bundled default one) to know what to look for. But most organizations eventually issue their own internal API tokens, and those obviously aren't in anyone's public detector catalog. TruffleHog supports a custom detectors config (--config) for exactly this: a keyword pre-filter, a regex for your token's shape, and — the part worth doing properly — a verification block that fires an HTTP request at your own internal service, so an internally-issued credential gets the same confirmed/unconfirmed treatment as an AWS or GitHub key.

# custom-detectors.yaml — teach TruffleHog about an internal token format
# The exact field names here have shifted across TruffleHog releases —
# treat this as the shape, and check the project's own examples/ folder
# for the current schema before committing one to a pipeline.
detectors:
  - name: acme-internal-api-token
    keywords:
      - "acme_key_"
    regex:
      token: 'acme_key_[A-Za-z0-9]{40}'
    verify:
      - endpoint: https://internal-api.acme.example/v1/whoami
        unsafe: false                      # never set true for a call with side effects
        headers:
          Authorization: "Bearer {token}"
        successRanges:
          - "200"

Notice the shape mirrors the built-in AWS and GitHub verifiers exactly: a cheap, read-only, authenticated endpoint, and a success signal that requires nothing more than a normal 200 response to confirm. That's the whole trick — you're not writing detection logic from scratch, you're describing your token's shape and pointing at the one endpoint that can honestly answer "is this still valid."

Day-to-day commands

☺ Like you're 10: One flag matters more than all the others — the one that says "only tell me about the keys that are actually still real."

# scan a local git repo — full history, every branch, by default
$ trufflehog git file://.

# the flag that matters most for a merge gate: only confirmed-live hits
$ trufflehog git file://. --only-verified

# CI diff-aware mode — only what's new on this branch since main
$ trufflehog git file://. --since-commit origin/main --branch feature/reporting-export

# scan an entire GitHub org in one pass (needs a token with read access)
$ trufflehog github --org=acme-corp --token=$GITHUB_TOKEN --only-verified

# scan a container image layer by layer, not just the flattened filesystem
$ trufflehog docker --image=ghcr.io/acme/checkout:1.4.3

# scan an S3 bucket — build artifacts, backups, log exports
$ trufflehog s3 --bucket=acme-build-artifacts

# scan a plain filesystem path, no git involved at all
$ trufflehog filesystem /path/to/extracted/artifact

# machine-readable output for a dashboard or a DefectDojo import
$ trufflehog git file://. --json --only-verified > results.json

# skip verification entirely — faster and works air-gapped, but back to "maybe"
$ trufflehog git file://. --no-verification

# fail the build on a verified hit — see the gotcha below before you skip this
$ trufflehog git file://. --only-verified --fail
⚠ Watch out — a verified secret does not fail your build by default

By default, trufflehog exits 0 whether or not it finds anything — including a confirmed, currently-active credential. It prints the finding; it does not fail the pipeline on its own. The --fail flag is what makes TruffleHog exit non-zero (documented as exit code 183 specifically, not the usual 1 — confirm this against your installed version's own --help, since exit-code conventions like this are exactly the sort of detail that can shift between major releases) when a verified result is present. A CI step that runs TruffleHog and only checks the job's overall pass/fail status, without --fail wired in, can have a live leaked credential sitting in its own log output while the build goes green. This is the single most common way a team believes they have a secrets gate and doesn't.

Gotchas and failure modes

☺ Like you're 10: Most of the surprises trace back to one thing — verification needs to actually reach the real internet, and not every credential can be checked at all.

TruffleHog versus gitleaks and detect-secrets

☺ Like you're 10: All three look for the same kind of thing — the difference is speed versus certainty, and most real pipelines use more than one.

None of these tools is strictly "better" — they trade speed and network dependence for certainty in opposite directions, and a mature pipeline typically layers more than one.

ToolDetection basisLive verificationConfigFits best at
TruffleHog~800 purpose-built detectors (keyword + regex per credential type)Yes — live, read-only API call against the real provider, for detector types that support itBuilt-in detectors need no rule file; custom detectors via a YAML configA slower, high-confidence CI gate; a scheduled full-history deep scan; onboarding a legacy repo
gitleaksRegex + Shannon entropy over a diff or full historyNo — network-free by designA TOML rule file, editable and diffablePre-commit hooks and fast per-PR diff scanning — the cheapest possible place to catch a leak
detect-secrets (Yelp)A plugin architecture over regex and entropy heuristicsNoA committed .secrets.baseline file that tracks accepted findings so re-scans only flag new onesPython-heavy shops already comfortable with a baseline-file workflow, often alongside pre-commit

The practical pairing this course keeps coming back to: run gitleaks (or detect-secrets) as the fast, zero-network layer at pre-commit and on every pull-request diff, and run TruffleHog with --only-verified --fail as the slower, higher-confidence layer — either a second CI stage on every push, or a scheduled deep scan across full history. gitleaks tells you something needs a look in milliseconds; TruffleHog tells you, with certainty, which of those somethings actually needs a rotation right now. See Static Analysis & Secrets Detection for the full worked example of a verified TruffleHog hit moving through triage, and the leaked credential triage drill for a timed, hands-on run of exactly that scenario.

🐘 Ellie's workshop · 15 min

On any repo you're authorized to scan — ideally an old one with some real history — run trufflehog git file://. --json and count how many total results come back. Then rerun with --only-verified added and count again. The gap between those two numbers is, concretely, how many "maybes" a pattern-only scanner like gitleaks would have handed a human to individually chase down. If anything comes back Verified, that's not a drill anymore — treat it exactly like the worked example in Static Analysis & Secrets Detection: rotate first, clean history second.

🎬 At the Shift-Left Squad
🦫

Benny the Beaver: gitleaks just flagged forty "API keys" across that legacy repo. Forty. I am not rotating forty credentials before lunch.

🐘

Ellie the Elephant: You don't have to — let me actually check them first. trufflehog git file://. --only-verified, running against the full history now.

🦊

Foxy: How is that different from what gitleaks already told us?

🐘

Ellie: gitleaks tells you a string is shaped like a key. I knock on the door — a read-only call to the real provider — and find out whether it still opens anything.

🐘

Ellie: ...Done. Thirty-nine of your forty are dead — rotated months ago, or plainly fake keys sitting in test fixtures. One is verified, live, right now — an AWS key from a commit eight months back.

🦫

Benny: One. I can rotate one before lunch.

🐢

Timmy the Turtle: Did the gate actually block the build on that one, though — or did it just print it and go green anyway?

🐘

Ellie: ...It would've gone green. I forgot --fail. Without it, a verified live credential can sit right there in the log and the pipeline still passes.

🦝

Rocky the Raccoon: A scanner that finds the leak and still lets it merge. That's not a false negative — that's a gate nobody actually finished building.

✓ Checkpoint

1. What does TruffleHog's live verification step actually do, and how is that different from what gitleaks does with the exact same matched string? 2. Name the pipeline stages a chunk of text passes through, in order, from source to a classified result. 3. Give two reasons an "Unverified" result from TruffleHog isn't always the same kind of uncertainty. 4. What does forgetting the --fail flag actually cost you in a CI pipeline? 5. When would you reach for gitleaks instead of TruffleHog as your primary, everyday gate, and why?

Check your answers
  1. TruffleHog takes a pattern match and fires a live, read-only API call against the real provider that would have issued it (for example AWS's sts:GetCallerIdentity), confirming whether the credential is currently active. gitleaks stops at the pattern/entropy match — it makes no network calls at all, so its hits are always unconfirmed "maybes."
  2. Source → Chunker → Decoder → Detector (keyword pre-filter plus a vendor-specific regex) → Verifier (a live API call, where one exists) → a classified result: Verified, Unverified, or an error reaching the provider.
  3. Any two of: it can mean the pattern matched but the live check simply came back inconclusive; it can mean the detector type has no verification path implemented at all, regardless of whether the credential is real; or it can mean a paired credential (like an AWS key and its secret) wasn't found close enough together to attempt verification even though both halves genuinely exist.
  4. Without --fail, TruffleHog exits 0 even when it finds and prints a verified, currently-active credential — a CI step that only checks the job's pass/fail status will show green on a build that actually contains a live leaked secret.
  5. As the fast, zero-network layer at pre-commit and on every pull-request diff, where TruffleHog's network-dependent verification would be too slow (or unreachable in a locked-down environment) to run on every keystroke — reserving TruffleHog's slower, higher-confidence verification for a CI stage or a scheduled full-history deep scan.