GitGuardian: 474 Leaked GitHub App Private Keys Still Authenticate

GitGuardian found 474 leaked GitHub App private keys still authenticating years after exposure -- including one tied to a CDC organization and one from BuildBuddy. Here's why this credential type never expires, and what would have to change to keep it off developer laptops.

The short version: GitGuardian tested 4,802 leaked GitHub App private keys pulled from a dataset of more than 500,000 exposed RSA keys and found that 474 of them — about 10% — still authenticated against GitHub’s API, covering 440 distinct Apps. Unlike personal access tokens or OAuth tokens, GitHub App private keys carry no expiration date; they stay valid until someone manually deletes them, sometimes for years. Two of the affected Apps belonged to organizations developers will recognize: a key tied to the CDC’s GitHub organization sat exposed for roughly 17 months, and a key for the dev-tools company BuildBuddy could have let an attacker rewrite the source behind its build CLI and servers. Neither incident involved a weak password. Both involved a credential type that was designed to be powerful and long-lived, then handled the same casual way as any other API key.

What GitGuardian actually found

GitGuardian, the secrets-detection vendor, pulled the sample from its own archive of publicly leaked secrets: over 500,000 exposed RSA private keys collected from public code. Narrowing that set to keys found in a GitHub-related context alongside a nearby App ID left 4,802 candidates. For each one, researchers signed a JSON Web Token and called GitHub’s /app endpoint — if the key were still valid, the API would return the App’s metadata.

474
of 4,802 tested keys still authenticated, spanning 440 distinct GitHub Apps
44
of those Apps carried full organization-administration privileges
207
could write to private repository content — enough to turn a leak into a takeover

The permission breakdown gets worse the further you look. 72% of the compromised Apps could read private repository content, 40 could administer self-hosted runners, and 98 could control workflows — any one of which is a plausible path to code execution on a company’s own infrastructure. Installation counts per App ranged from zero up to 303, and 59% of the affected Apps had only a single installation, suggesting most were internal tools built by one team rather than public integrations. In 156 cases, the key had leaked in a repository the App’s own maintainer didn’t even own — forked, mirrored, or copied code carrying someone else’s credential along with it.

Why "rotate your API keys" checklists miss this credential entirely

Most credential-hygiene guidance is built around tokens that fail safely by default. Personal access tokens can be scoped to expire in 30, 60, or 90 days. OAuth access tokens typically live for an hour and refresh behind the scenes. GitHub App private keys work differently: the RSA key itself is used to sign a JWT, which is exchanged for a short-lived installation access token — usually valid for about an hour. That part expires fine. The problem is the signing key that mints those tokens. It has no TTL. It stays valid indefinitely, for as long as the App exists, until a human being goes into GitHub’s settings and deletes it.

That single design detail is why a key that leaked in a commit in 2020, tied to the unmaintained Crusher.dev testing framework, was still functional when GitGuardian tested it — three years after the project stopped being maintained. Nobody had to make a mistake twice. They just had to never notice the first one.

Case one: a federal health agency’s key, exposed for 17 months

The most sensitive example GitGuardian disclosed involves an organization called cdcent and a repository belonging to CDCGov, the official GitHub organization of the U.S. Centers for Disease Control and Prevention.

1 · Leak

A private key for an App owned by cdcent was exposed in April 2025 inside a CDCGov repository. The App was installed only in the cdcent organization, with write access to two private repositories.

2 · Exposure window

One of those two repositories appears, based on public documentation, to mediate between CDCGov’s main repositories and the agency’s Azure infrastructure. GitGuardian said the key could plausibly have enabled arbitrary code execution inside CDC’s Azure tenant, though researchers did not interact with the repository to confirm it.

3 · Disclosure

GitGuardian reported the exposure through the HHS responsible-disclosure portal on September 4, 2026.

4 · Revocation

The credentials were revoked on September 18, 2026 — roughly 17 months after the key first leaked.

To be clear about what is and isn’t known: GitGuardian did not claim the key was exploited, and it deliberately avoided testing its write access against a live production repository. The finding is that the key could authenticate and could write for a year and a half without anyone at the agency noticing or rotating it.

Case two: BuildBuddy’s own development key

The second named case is smaller in blast radius but easier to picture, because it happened to a company whose entire product is developer infrastructure. BuildBuddy builds remote build and caching tools for Bazel, the open-source build system.

1 · Leak

A private key for an App called "BuildBuddy (local)" leaked in June 2025 inside one of the company’s own repositories. The App was meant purely for internal development and was installed on only 10 organizations, including BuildBuddy’s own buildbuddy-io account.

2 · Scope of access

The App held write and administer permissions on buildbuddy-io/buildbuddy, the repository containing the source for both the client CLI and the server components of the platform. An attacker with write access there could, in theory, have tampered with code that ships to every BuildBuddy CLI user and every company running BuildBuddy’s server components on their own infrastructure.

3 · Response

After GitGuardian’s report, BuildBuddy’s security team took the App down quickly. The company investigated and found no evidence of malicious exploitation.

GitGuardian also flagged a third, larger-scale example: a key for an App called "Access Tokens for GitHub Actions," leaked in a January 2024 commit that was likely accidental. That App had 304 installations at the time, including organizations like Civica and Sierra Nevada Corp, with permissions to modify repository content and administer organizations. Its maintainer rotated the key promptly once notified.

What an egress-proxy model would — and wouldn’t — have changed

It’s worth being precise here, because GitHub App keys don’t behave like a typical bearer token you'd inject into an outbound Authorization header. The raw RSA private key is used to sign a JWT locally, inside whatever process holds the key — a CI job, a server, a developer’s laptop. That signing step is what makes this credential class awkward to protect: the code doing the signing needs the actual key material in memory or on disk, at least momentarily.

That said, the signing operation itself doesn’t have to happen inside the same process that runs your application or CI pipeline. In an architecture where the private key lives only inside a dedicated secrets/proxy layer — the model KnoxCall's egress-gateway approach is built around — the signing happens server-side, and only the resulting short-lived installation token (already capped around an hour by GitHub) is ever handed to the runner, the build agent, or the developer's shell. No .pem file sits in a repo checkout, an env var, or a CI log for someone to commit or scrape.

Applied to these two incidents specifically: the CDC key leaked because it ended up committed inside a CDCGov repository, and the BuildBuddy key leaked inside the company’s own repository. In both cases, a human or a process had the raw key file somewhere reachable enough to accidentally check it into version control. If the raw key had never left a signing service in the first place — if engineers only ever received the ephemeral installation token their code actually needed — there would have been no private key sitting on disk to commit by mistake.

What an egress-proxy model would not have done is retroactively un-leak the Crusher.dev key that had been sitting in a public commit since 2020, or make GitHub start expiring App keys automatically. Architecture changes what's exposed to the developer going forward. It doesn't substitute for actually revoking a key once it's out, and GitGuardian's whole point stands regardless of architecture: someone still has to look.

Key takeaway: GitHub App private keys are worth treating as tier-one secrets — closer to a cloud root credential than an API key — specifically because nothing forces you to rotate them. If a system doesn't expire a secret for you, your own controls have to.

What to actually do this week

  • Inventory every GitHub App your org owns or has installed, and confirm who currently holds each private key file. Most teams can name their PATs; far fewer can name their Apps.
  • Rotate any App key that has ever touched a laptop, a CI log, or a committed file — even briefly, even in a private repo. A key that was exposed for ten minutes in 2022 is functionally identical to one exposed for ten minutes today.
  • Stop distributing the raw .pem file to CI runners or developer machines where you can avoid it. Generate installation tokens through a signing service that never releases the private key itself, and give runners only the short-lived token.
  • Extend secret scanning to RSA-format keys, not just token-shaped strings. GitGuardian's data set specifically included keys sitting in repositories the App's own maintainer didn't own — forks and mirrors carry credentials along with the code.
  • Treat GitHub App permissions as you would cloud IAM roles. An App with organization-admin, runner-admin, and workflow-control scopes is not a convenience integration; it's a standing grant of infrastructure control.

For a broader look at why secrets keep ending up in places they shouldn't, see our related coverage on credential attacks no checklist can stop and on why secrets managers alone can't protect keys that still reach the process.

Frequently asked questions

What did GitGuardian find about leaked GitHub App private keys?

GitGuardian tested 4,802 leaked GitHub App private keys pulled from over 500,000 exposed RSA keys in its public-leak dataset and found 474 -- about 10% -- still authenticated to GitHub's API, representing 440 distinct Apps. Some of those Apps carried organization-admin, self-hosted-runner-admin, or workflow-control permissions.

Do GitHub App private keys expire?

No. GitHub App private keys have no built-in expiration and remain valid until an administrator manually deletes them in GitHub's settings. The short-lived installation tokens they generate expire after about an hour, but the signing key itself does not.

What happened with the CDC-linked GitHub App key?

A private key for an App owned by an organization called cdcent leaked in April 2025 inside a repository belonging to CDCGov, the CDC's official GitHub organization. It had write access to two private repositories, one of which reportedly mediates access to the CDC's Azure infrastructure. GitGuardian disclosed it through the HHS reporting portal on September 4, 2026, and the credentials were revoked on September 18, 2026 -- about 17 months after the leak.

What happened with the BuildBuddy GitHub key leak?

A private key for BuildBuddy's internal development App leaked in June 2025 inside the company's own repository. It had write and admin permissions on BuildBuddy's main repository, which contains the source for its CLI and server components. BuildBuddy took the App down after GitGuardian's disclosure and found no evidence of malicious use.

How can organizations protect against leaked GitHub App keys?

Inventory every GitHub App your org owns, rotate any key that has ever touched a laptop, CI log, or committed file, and avoid distributing the raw private key file to runners or developer machines where possible. Extending secret scanning to RSA-format keys and treating App permissions like cloud IAM roles also reduces exposure.

Sources

  1. GitHub App Private Keys: 474 Leaked Keys Still Work (GitGuardian)
  2. Hundreds of Leaked GitHub App Keys Still Authenticate (Infosecurity Magazine)
  3. GitHub App keys can still enable takeovers long after they are forgotten (CSO Online)
  4. Hundreds of GitHub App private keys leaked, granting broad access (MSSP Alert)
  5. Leaked GitHub key exposed CDC-linked code to poisoning risk (Cybernews)

Stop shipping long-lived keys to processes that don't need them

Whether it's a GitHub App private key, a cloud credential, or an LLM API key, KnoxCall's egress-proxy model keeps the raw secret at the wire and hands your CI runners and app processes only the short-lived token they actually need.

Start Free →

Or get new posts by email. Double opt-in, unsubscribe anytime.