Which credential do you rotate first?
Your TruffleHog run across a compromised laptop comes back with hundreds of credentials: AWS keys in shell history, a GitHub PAT in a config file, OAuth tokens cached under .config, a service-account JSON someone dropped in ~/Downloads. The scanner did its job. Finding them was the easy part.
It won't tell you which of these still reach production, or which one you rotate first.
The question detection leaves open
Secret scanners are pattern matchers. gitleaks, TruffleHog, and GitGuardian are good at the haystack problem: given a pile of code, git history, or files, find the things shaped like credentials. Some go one step further and tell you a key is live; TruffleHog's analyze will even enumerate permissions for about a dozen providers. What none of them do is take a pile of live credentials and rank them against each other by what each one reaches.
So you fall back to doing it by hand. You take the AWS key, run sts:GetCallerIdentity, check whether it's prod, see if it can read Secrets Manager. Then the next one. Then the GitHub token, the Stripe key, the Postgres connection string. During an incident, with a rotation clock running, across hundreds of creds. It's a slog. A credential gives away nothing about its own reach; you find out what an AWS key unlocks by asking AWS, one call at a time. That manual triage is exactly the work geiger automates.
geiger is built for this. Pipe it any credential-bearing text or directory and it recognizes the credentials inside (over a hundred types today, and growing), runs read-only recon with each, and ranks what they reach by blast radius. Point it straight at the scanner's report and it starts where the scanner stopped:
geiger --live --from-trufflehog trufflehog.json
You hand it the haystack's output. It hands you back a rotate-first queue.
Blast radius, not a match count
The ranking is useful, so lets be precise about what drives it. geiger scores each credential on a composite of capability, reach, and sensitivity. The score is relative, not absolute: it sorts this set of findings against each other so the worst should float to the top.
Capability is what separates a real problem from a warning. A billed-usage API key that can run up a bill is a warning. A key that runs code, wipes devices, restores backups, or reads other secrets is a force multiplier, and geiger tiers it accordingly. Tiers run CRITICAL, HIGH, MEDIUM, LOW, INFO, DEAD. A key that comes back DEAD is one you can likely not worry about, which during an incident is its own kind of useful.
The triage is also yours to bias. Pass your crown jewels and anything touching them gets boosted:
geiger --live --context '1234567890,acme-prod,billing-service' ./repo
Now the production account number and your billing service force their findings up the queue, regardless of the generic score. You're triaging against your environment, not a textbook severity table.
Try it without a real secret
geiger doesn't touch the network until you tell it to. Dry-run is the default: it recognizes the credential and prints the exact read-only calls it would make, and nothing leaves your machine. You can prove this to yourself on AWS's published example keys:
printf 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE\nAWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n' | geiger
That prints the plan: sts:GetCallerIdentity, then a couple of count calls to size reach. Add --live with a real credential and it actually runs them and returns the impact note. The recon pipeline is small and legible: recognize, authenticate, run the identity call, run a few count calls, write the note.
The same exploration a worm performs
A leaked key is rarely the end of the chain. The key reads a secrets manager; the secrets manager holds ten more credentials; those reach further. They sit in an access broker's queue until purchased. Static triage of the first key understates the real exposure.
--intrusive follows that chain, still read-only. It connects to databases with a read-only session and a fixed query allowlist, reads local SQLite and IDE token stores in place, hits cluster APIs, and follows secrets-store reads, draining Vault, Doppler, 1Password, and the cloud secret managers, then recursively triaging each secret it pulls out. That is the same thing a supply-chain worm like Shai-Hulud runs when it lands on a host. Running it yourself, deliberately and read-only, is how you see the blast radius an attacker would, instead of guessing at it.
Read-only by construction
A tool that exercises live credentials during an incident has to be trustworthy about what it does, and "trust me" doesn't quite clear that bar. geiger's safety is structural.
Read-only is enforced in the code, not the docs. One HTTP client allows only GET and HEAD plus a short allowlist of read-only POSTs: STS GetCallerIdentity, the Kubernetes SelfSubjectRulesReview, the single OAuth token exchange. Database recon runs in a read-only session against a fixed query allowlist. Local stores open read-only. A guard test enforces this across all modules.
The rest follows the same logic. --live is required and always prints the real destinations it will hit, including the provider audit logs your calls will land in. Recon identifies itself as geiger/vN.N.N and makes no attempt to evade detection, so a defender watching the other side can better attribute those calls. Secrets are never printed or stored - they're redacted in output and scrubbed from URLs, headers, and errors.
geiger is MIT-licensed and ships as a single Go binary. Grab a release binary or go build ./cmd/geiger from github.com/puck-security/geiger.
What it won't do
geiger triages a credential you already have. It is not a host credential-extraction tool per se: it won't try to read the macOS Keychain, unwrap Windows DPAPI blobs, or pull secrets out of LSASS, because reading those are arguably where creds should be and have their own unique telemetry EDR is well poised to analyze.
Recognition uses gitleaks' shapes plus geiger's own recognizers, so a type it doesn't know is reported unknown rather than ignored. And the score is likely impact, not proof: geiger ranks blast radius, it does not graph every IAM privilege-escalation path. For that, reach for PMapper, CloudFox, or ScoutSuite. geiger's job is to tell you which credential is worth pointing them at first.
Where it fits
geiger is dual-use, and the two uses are the same read-only question from opposite sides. The incident responder asks "how bad is this?" The pentester asks "what does this key reach?" Both want a live credential characterized and ranked, without changing anything on the far end.
That question, what can an attacker actually reach, is the whole of what Puck Security builds. geiger is the offline, single-credential edge of it: point it at a credential you were handed or one sitting on disk and get back what it reaches. Puck Scout asks the same read-only question across a fleet, driven by your own AI over MCP. The principle holds at every scale: map the reach, change nothing.
It does not replace your scanners. Detection is their job and they're good at it. geiger consumes their output and answers the question they leave open: now that you found it, is it live, what does it reach, and in what order do you rotate. The one caveat that matters: it exercises real credentials, so run it only on the ones you're entitled to triage.
geiger is open source and MIT-licensed: github.com/puck-security/geiger.