Skip to content
>_ITDITDWeb Security Platform

Security Guides

543,699 credentials published on GitHub still worked (2026 study): why you must revoke, not delete, and what developers should do

A 2026 study found 543,699 credentials in public repos still worked. What the numbers mean, why deleting isn't enough, and what to do: revoke, check usage, replace.

Published 2026-10-04 Updated 2026-10-04 Last verified 2026-10-04 12 min read

Who this is for: developers who keep code in public repositories such as GitHub, and companies that run APIs. This article restates the numbers from a security company's study in this site's own words. It does not cover how to find other people's credentials.

What this study is (not an official GitHub study)

On 29 September 2026, Truffle Security, a security company that sells secret-scanning tools, published a study of credentials left in public repositories. As a vendor of detection tools, the publisher has a commercial interest in the topic. This article uses the study's numbers as reported and marks this site's interpretation separately.

GitHub did not leak anything. The credentials were written into code and published by the owners of each repository. GitHub's role is to provide prevention features such as push protection (blocking pushes that contain secrets), and as shown below, those features cover a limited set of types.

How the study worked, and how to read the numbers

~224.5M
Repositories examined (The Stack v3)
27-28 Jul 2026
When liveness was tested
Default branch only
No commit history included
Authenticated
What “live” means (permissions and abuse not checked)
  • The source data is The Stack v3, a dataset of public repositories collected by a third party for training LLMs (large language models). Collection closed on 7 August 2025.
  • Only the default branch (such as main) at collection time was examined. Older commits, other branches and anything removed earlier are not included. It is not a scan of all public code on GitHub.
  • "Live" means the provider confirmed the credential still authenticated on 27-28 July 2026. Some may have been revoked since.
  • The time since exposure is counted from the last modification date of the file containing the credential. The study notes this tends to understate the real age.
  • Some types are left out of certain figures. Google API keys were only tested against Gemini, and private keys cannot be tested without the host they belong to, so neither is included in the per-type survival figures.

The numbers: what was left, and how much

543,699
Unique credentials live at test time
~1.1M
Total appearances across files and repositories
784 days
Median time since exposure
6.3+ years
Age of the oldest 10% (oldest from 2009)

In the week of 29 February 2024, GitHub began turning on push protection by default for pushes to public repositories for all users. According to the study, 199,843 (36.8%) of the 543,699 live credentials appeared after that date.

In addition, 51.8% of the live credentials were connection strings, Google API keys or private keys, types that push protection does not block by default. For the types that push protection does cover, the number of leaks per million files fell by about 53% when comparing the 12 months before and after the change. Types it does not cover fell by only about 7%. The study itself notes other factors may be mixed in, such as cloud providers pushing customers toward short-lived credentials during the same period.

How many survived, by type

The table below recalculates percentages from the counts the study published. "Found" is the number of credentials found on default branches; "Live" is how many of those still authenticated at test time.

TypeFoundLiveLive share
npm tokens101,88610.001%
Hugging Face tokens30,437150.05%
GitHub tokens73,0482600.4%
Slack tokens8,9031982.2%
Stripe keys (including test-mode keys)124,1324,4933.6%
AWS access keys82,4116,8198.3%
Docker Hub tokens3,7901,24432.8%
SendGrid keys22,8009,18940.3%
Google Cloud service account keys126,96369,04154.4%
MySQL connection strings2,4211,80674.6%
PostgreSQL connection strings12,98511,46588.3%
MongoDB connection stringsNot counted51,067—

The detector used for MongoDB only records strings it managed to connect with, so no share can be calculated and the type is left out of the survival figures. Only the live count is reported.

Why the types differ so much

The difference comes less from how easy the credentials are to find and more from whether anyone stops them after they are found. Within what we could confirm in each provider's official documentation, the picture is as follows.

The issuer stops them automatically

  • GitHub tokens: GitHub documents that valid tokens pushed to a public repository or gist are revoked automatically
  • npm tokens: since 2019, npm revokes valid tokens found via GitHub and emails the owner
  • Hugging Face: an official mechanism lets anyone, not only the owner, invalidate a leaked token

Only you can stop them

  • Database connection strings: there is no issuer; they work until you change the password
  • Many API keys: what an issuer does after GitHub notifies it is up to the issuer
  • Private keys for your own servers: only the owner knows where they are used

GitHub's secret scanning partner program notifies issuers about credentials found in public repositories. GitHub's documentation recommends treating any secret it reports as public and compromised, but leaves the implementation to the issuer. The issuer decides whether to revoke, reissue or contact the user.

The two cloud providers respond in ways that are not the same as full revocation.

  • AWS: AWS attaches a managed policy called "AWSCompromisedKeyQuarantineV3" to an IAM user whose access key may have been exposed. It denies certain actions, such as launching instances or changing IAM, but does not delete the key. AWS asks customers not to remove the policy and to follow the instructions in the support case it opens.
  • Google Cloud: since 16 June 2024, service account keys detected in places such as public repositories are disabled automatically by default. Organizations can opt out (WAIT_FOR_ABUSE) with the organization policy constraint iam.serviceAccountKeyExposureResponse. The study still found more than half live; it does not explain why.

This site's view: deleting leaves copies elsewhere

The study itself used a dataset built in August 2025. If an owner deleted a file after that, the credential is still in the dataset. The same is true of forks, other people's clones, mirrors, and search or AI training data.

So treat "pushed to a public repository" as "leaked", and invalidate the credential on the issuer's side. Rewriting history is cleanup to stop further spread.

Your repository

Delete or rewrite history

→

Forks, clones, mirrors

On other people's machines

→

Datasets, archives

Copies as of collection time

→

Revoked by the issuer

Every copy stops working

Where a credential pushed to a public repository ends up. Only the leftmost copy can be removed from your own repository.

If you find you leaked one

1

Revoke the key with the issuer

Disable the key or token in the console or CLI. For a database connection string, change that user's password or recreate the user. A short outage costs less than abuse, so do not put this off.
2

Check for use and charges

Look for activity you don't recognize between the leak and the revocation: CloudTrail on AWS, Cloud Audit Logs on Google Cloud, and the usage history and bill in the dashboard of email-sending or payment services. If AWS has attached the quarantine policy or opened a support case, follow its instructions.
3

Issue a new key and replace it

Do not write the new key into code; load it from environment variables or a secrets manager. Take the chance to narrow its permissions, allowed source IPs and expiry.
4

Clean the history last

Remove it from history with a tool such as git filter-repo and force-push. Copies in forks and on other machines remain, so this does not replace revocation.

If you find someone else's key, don't test it

If you come across a credential in someone else's repository, do not check whether it works. Tell the owner or the issuer. For supported types in public GitHub repositories, GitHub notifies the issuer.

Preventing leaks

Push protection helps, but it is not enough on its own. As the numbers show, types it does not block by default pass straight through, and users can bypass a block by choosing a reason. Combine it with the following.

  • Scan before you commit: stop secrets on your own machine before the push with a scanner such as gitleaks (see stop secrets before they commit with gitleaks).
  • Scan the history of old repositories: push protection does nothing for commits made before it was turned on. Scan the full history of neglected and archived repositories at least once.
  • Use short-lived credentials: GitHub Actions can connect to AWS or Google Cloud with OIDC (receiving a credential valid only for a short time on each run) instead of storing a long-lived key. Hugging Face offers the same approach.
  • Narrow what each key can do: read-only, specific APIs only, source IP or referrer restrictions, and an expiry date. This limits what a leak can cost you.
  • Keep databases off the internet: a leaked connection string is useless if it cannot be reached from outside. Database connection strings were the longest-lived type in the table.

The basics of keeping secrets out of code are in what's actually dangerous about .env and API keys, and secrets left on web servers are covered in auditing public directories.

For companies that run APIs

What separated the top of the table from the bottom was whether the issuer stops leaked keys automatically. As the party that protects your users' keys, consider:

  • Joining GitHub's secret scanning partner program, and revoking valid keys and notifying users when you are notified
  • Giving keys a distinctive prefix (for example, one that starts with your service name) so they are easy to detect
  • Offering a channel or API through which anyone can report and invalidate a leaked key
  • Making expiring keys and narrowly scoped keys the default

Sources (public record)

The numbers in this article come from the public sources below. We have not reproduced the study's text or charts; we used only its counts and reorganized them.

FAQ

QIs this an official GitHub study?
A

No. It was published on 29 September 2026 by Truffle Security, a security company that provides secret-scanning tools. GitHub did not leak anything: the credentials were written into code and published by the owners of each repository. GitHub provides prevention features such as push protection and secret scanning, but they cover a limited set of credential types.

QI committed an API key. Is deleting the file or rewriting history enough?
A

Once you push to a public repository, copies may already exist in forks, other people's clones, mirrors and datasets like the one used in this study. Deleting the file or rewriting history does not remove those copies. The first step is to revoke the key with its issuer and issue a new one. Clean the history afterwards.

QWon't the issuer revoke a leaked key automatically?
A

It depends on the issuer. GitHub's documentation says valid GitHub tokens pushed to a public repository are revoked automatically, and npm has done the same for its tokens since 2019. Under GitHub's secret scanning partner program, however, what an issuer does after being notified is left to the issuer. Credentials with no issuer behind them, such as database connection strings, are not stopped by anyone.

QDoes GitHub push protection prevent this?
A

Partly. By default, push protection blocks specific token formats listed in its supported patterns. GitHub's pattern list shows Google API keys and MongoDB and PostgreSQL connection strings as alert-only, without push protection. Users can also bypass a block by choosing a reason, or turn the feature off. Combine it with pre-commit scanning and short-lived credentials.

QWhat does "live" mean in the study?
A

The study matched credentials by pattern, then asked each provider whether the credential still authenticated on 27-28 July 2026. It did not check what permissions they had or whether they were abused. Some may have been revoked since.