Skip to content

Truffle: 543,699 live credentials sitting in public GitHub repos

Truffle Security scanned 224M public GitHub repos and found 543,699 credentials that still authenticated in July 2026 — including 69,041 valid Google Cloud service-account keys.

Published 3 min read

Truffle Security scanned 224 million public GitHub repositories and found 543,699 unique credentials that still authenticated when tested in July 2026 — not expired, not rotated, live. The write-up, GitHub Repos Exposed 543,699 Credentials. Nobody Revoked Them., is the primary; the numbers below are theirs.

What it demonstrates

The finding isn't that secrets get committed — everyone knows that. It's that they stay valid for years after exposure:

  • Median exposure: 784 days. The oldest still-working credential was committed in 2009; roughly 10% were older than 6.3 years.
  • Google Cloud service accounts: 126,963 found, 69,041 still valid — more than half never revoked. These are often high-privilege, non-interactive keys, exactly the kind that make a quiet pivot into cloud infrastructure.
  • npm tokens: 101,886 found, only 1 still worked. The contrast is the story — npm's automated revocation pipeline works; most other issuers' don't.

The gap between npm and Google Cloud is the actionable insight: the problem isn't detection, it's revocation discipline. A leaked secret nobody rotates is a leaked secret an attacker can use at leisure.

Limits and caveats

  • The corpus was a crawl assembled for LLM-training that closed August 7, 2025; validity testing ran in July 2026. So "live in July 2026" is the hard claim; the exposure set is up to ~11 months stale at the edges.
  • "Still authenticated" means the key returned a valid response to a benign check, not that it was abused. Truffle tested validity, not exploitation.
  • Counts are for public repos only. Private-repo and CI-log exposure is a separate, larger problem this study doesn't touch.

On GitHub's own control: push protection has been on by default since February 2024, yet Truffle reports just under 200,000 credentials pushed after that date, and says 51.8% of what's still live is in a format push protection doesn't recognize. The block halves the rate for recognized credential shapes — it is not a backstop for custom or uncommon ones.

What to do

  1. Rotate, don't just delete. Removing a secret from the latest commit leaves it in history and, more importantly, still valid at the provider. Revoke it at the source first.
  2. Scan full history, not HEAD. Use TruffleHog or your scanner of choice against the whole git history and any forks.
  3. Set expiration on everything that supports it. Short-lived, auto-expiring credentials turn a leak into a time-boxed problem.
  4. Audit Google Cloud service-account keys specifically. Prefer workload identity federation over long-lived JSON keys; disable and delete keys you can't tie to a live workload.
  5. Don't rely on push protection alone for non-standard secret formats — add server-side secret scanning that you control.

Context

Half a million live keys in public code is a floor, not a ceiling — public repos are simply the part that's easy to measure, with private repos, CI logs, and container layers unquantified alongside it. The durable lesson for AppSec teams is unglamorous: committing a secret is a mistake, but not revoking it is the one that gets you owned, sometimes a decade later.

Related stories