Skip to content
enterprise

The GitHub Keys That Never Die

A forgotten integration can outlive the project, the engineer, and the security assumptions that once justified it. The uncomfortable twist: short-lived tokens may still be minted by a credential with no built-in expiration.

Eleanor Shaw
The GitHub Keys That Never Die

The token expires. The key doesn’t.

GitHub App authentication hinges on a private key that generates a JSON Web Token (JWT) with a maximum 10-minute lifespan. This JWT then requests an installation access token, valid for up to one hour. GitHub strictly enforces these downstream token expirations, creating an illusion of transient access.

However, the root private key, the source of these credentials, possesses no native time-to-live (TTL). It can perpetually mint new tokens until explicitly revoked. This fundamental architectural choice means a compromised or forgotten key remains a persistent threat, unlike the short-lived tokens it produces.

While some argue this mirrors SSH key behavior, which also commonly lacks platform-enforced expiration, the scope of GitHub App permissions dramatically elevates the risk. Apps often wield broad, multi-repository access, including:

  • Organization administrative privileges
  • Write access to private code
  • Control over self-hosted runners and workflow execution

GitGuardian’s research found 474 active keys, with 44 granting full org-admin rights. One key, linked to the US CDC, provided write access to private code for 17 months after its leak. This highlights why unmanaged GitHub App keys pose a significant, enduring governance risk, far beyond that of a typical SSH key.

474 leaked keys still opened the door

GitGuardian’s recent research uncovered a stark reality: of over 500,000 exposed RSA keys, 4,802 were linked to a GitHub App ID. A staggering 474 of these keys still authenticated, representing 440 distinct apps, despite being publicly exposed. This demonstrates a critical vulnerability in the security chain.

The implications of these persistent exposures are severe. Forty-four valid apps had full organization-admin access, while 72% could read private repositories. Furthermore, 207 apps possessed write permissions, opening the door to arbitrary code injection and pipeline poisoning, a significant supply-chain security risk.

The problem’s persistence is troubling. one Crusher.dev key had been public since 2020 and remained active. A key linked to the US CDC reportedly remained valid for 17 months after its exposure. Another widely used app, "Access Tokens for GitHub Actions," leaked a private key in January 2024, affecting roughly 300 organizations, including defense contractor Sierra Nevada Corp.

These examples underscore the danger of GitHub App private keys: unlike the short-lived JWTs and installation access tokens they mint, the root private keys themselves have no native expiration. This architectural oversight transforms a single leak into a perpetual security threat, demanding immediate attention and robust key rotation strategies.

A forgotten app can become a supply-chain foothold

A forgotten app presents a significant supply-chain foothold. Leaked keys can enable an attacker to read private code, write to repositories, manipulate workflows, or administer self-hosted runners. Such access directly facilitates code tampering, CI/CD compromise, and ultimately, organizational takeover.

Stale integrations are easily overlooked. GitGuardian found 59% of the 440 distinct apps with active keys had only one installation, often for ad-hoc automation. When engineers depart or projects are abandoned, ownership of these apps frequently disappears, leaving a persistent vulnerability. The Crusher.dev app key, exposed since 2020, remained active years after the project ceased maintenance.

The US Centers for Disease Control and Prevention (CDC) organization, for example, had a leaked private key with write access to private repositories for 17 months, mediating access to its Microsoft Azure infrastructure. Similarly, the widely used "Access Tokens for GitHub Actions" app leaked a private key, exposing approximately 300 organizations.

While a valid key does not automatically prove active exploitation, it signifies persistent exposure. Attackers, once they obtain a valid key, can act with the app’s granted permissions at any time. For further details on these persistent threats, see GitGuardian’s research: GitHub App Private Keys: 474 Leaked Keys Still Work. This highlights the critical need for rigorous management of GitHub App private keys and their associated permissions to mitigate supply-chain risks.

Enjoying this? Get one like it in your inbox each morning.

one email a day · unsubscribe in two clicks · no third-party tracking

Rotate without downtime—and retire what nobody owns

App owners must implement a robust key rotation strategy. Generate a new private key, deploy and verify its functionality, then revoke the old one. GitHub allows up to 25 active private keys per app, enabling staged rotation without service interruption.

Establish a documented rotation cadence, secure key storage protocols, and integrate secret scanning across all repositories, including developer-owned public forks. Enforce least-privilege access, limiting app permissions to only the repositories and actions strictly required for its function. This minimizes the blast radius of any potential compromise.

Organization administrators face a critical mandate to audit installed apps. Identify and assign accountable owners for every integration. Promptly remove abandoned or unmaintained apps, as these become prime targets for attackers seeking a persistent foothold.

Finally, verify that all surviving apps operate with the absolute minimum necessary permissions. Reviewing and tightening these access controls reduces the attack surface, preventing a forgotten app from becoming an open door to your organization’s most sensitive assets.

Frequently Asked Questions

Do GitHub App private keys expire automatically?

No. GitHub App private keys do not have a built-in expiration date, so owners must rotate and revoke them.

How can an unexpired GitHub App key be used?

It can sign a short-lived JWT, which can be exchanged for an installation access token that lasts up to one hour.

How many GitHub App private keys can be active at once?

GitHub allows up to 25 private keys for an app, enabling teams to deploy a replacement before deleting the old key.

What should an organization do about apps nobody maintains?

Audit installed GitHub Apps, remove stale or unowned integrations, and restrict the permissions and repositories granted to those that remain.

Found this useful? Share it.

For builders

Want Stork to write one of these about your product?

Send us a URL. We use the product, form a view, and publish what we actually think — in 8 languages, labeled Sponsored, with no copy approval on your side. That last part is what makes it worth quoting.

See how it works$199 · AI tools & software only

For builders

This page is doing a job for someone else’s tool.

AI agents read it. Buyers land on it. It answers in eight languages and over MCP. Your tool can have one like it — live in 24 hours.