P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

543,699 working credentials in public GitHub code: at least 63% predate default push protection

Truffle Security found 543,699 credentials from a crawl of public GitHub code still working in July. On its own counts 63 per cent are dated before push protection became the default, so at least that share is older than the block, and over half are in shapes it does not block.

By Parminder Kumar Sharma · · 18 min read

Editorial illustration for the briefing: 543,699 working credentials in public GitHub code: at least 63% predate default push protection

At least 343,856 of the 543,699 date from before the block

Truffle Security's headline number is 543,699 credentials that still worked when it tested them on 27 and 28 July 2026. Its own chart splits them three ways. 199,843, or 36.8 per cent, carry a date after GitHub began switching push protection on by default: GitHub's announcement is dated 29 February 2024 and says the rollout began that week. The other 343,856, or 63.2 per cent, carry an earlier date: 245,959 from before secret scanning alerts became free for public repositories on 28 February 2023, and 97,897 from the year after. The 343,856 is our subtraction; the post gives the two pieces.

BleepingComputer's report says the credentials were still valid in July "despite the platform's security measures". On the post's own dating, most of them were committed before the default block existed. That framing fits at most a little over a third of them, and "at most" is the right phrase, because the dates can only err late (more on that below).

Here is what the split does not establish. It does not show that anyone other than Truffle used any of the 543,699: BleepingComputer itself notes that the findings do not reveal what share were stolen and abused. It does not show that a control failed, because the post does not say how many of the 199,843 were in shapes push protection blocks. It does not say how Truffle tested credentials it did not own, beyond asking the issuer whether each still works. And it was published by a company that sells secret scanning, whose advice includes scanning your own history rather than trusting a block at push time.

What was counted, and what live means

The corpus is The Stack v3, a Hugging Face dataset of public GitHub code built for training code models. Its dataset card says it is a direct crawl of each repository's default branch at its latest commit, that the crawl completed on 7 August 2025, that no git history is collected, and that forks were downloaded only when they had at least five stars. So "public GitHub repositories" here means 224 million repositories as they stood when the crawl finished, without history, without other branches and without low-star forks. Truffle says as much: anything force pushed away, moved to another branch or committed and reverted before August 2025 is invisible, and "the real population is larger".

Candidates were found by pattern matching. Each was then tested against the service that issued it on 27 and 28 July 2026, 354 days after the crawl closed, counting to 27 July (our arithmetic). A credential counted as live only if the issuer said it still worked. Truffle's open-source scanner, TruffleHog, describes that step as logging in to confirm whether a secret is live. The post does not say which tool it used or what each per-provider check did, and that matters, because a login with a stranger's credential is itself a use of it. The post does not discuss the limits it set or its basis for testing. Its June 2026 Hugging Face post did say, for that scan, that checks were limited to verification and metadata such as database size statistics, with no rows read and nothing modified. A team that wants to run the same test on credentials that are not its own should take legal advice first; in the UK the Computer Misuse Act 1990 is where that question starts.

Then the counting. The scan returned 544,069 distinct live credentials, keyed by value, so one key found in 62 repositories counts once. Of those, 543,701 could be traced to a file in the corpus metadata and 543,699 carry a usable date. Those 543,699 sit behind 1,103,438 separate exposures, about two per credential (our division). This is a count of distinct credentials, not of repositories and not of people.

Four boxes show Truffle's counts from 224,553,295 repositories to 543,699 dated live credentials. Two bars of the same 543,699 are drawn to scale: 63.2 per cent dated before push protection became the default and 36.8 per cent after; 51.8 per cent in shapes the default block does not cover. A band says how the bars cross is not stated. A last row shows push protection, secret scanning and the partner programme.
Drawn from Truffle Security's post of 29 September 2026 and GitHub's documentation, read on 30 September 2026. Derived figures are marked.

The diagram keeps two cohorts apart, as the post does. The 4,941,427 values are everything the scan matched that can identify itself (a vendor prefix, a connection string with a password, a private key block, a service account file), live or not. Truffle uses them for the survival rates further down and excludes 3,289,226 Google API keys because it tested those only against Gemini. The 544,069 are what authenticated. The post does not give the overlap, so the boxes are not a strict funnel.

What each figure establishes, and what it does not

Figures from Truffle Security's post of 29 September 2026 and BleepingComputer's report of 30 September 2026. Derived means our arithmetic.

FigureWhat it establishesWhat it does not establish
543,699 live credentialsDistinct values the issuers confirmed on 27 and 28 July 2026, found by pattern in a crawl that closed on 7 August 2025.That anyone else used them, that they are still in public code in July 2026, or how many exist on GitHub: no history, other branches or low-star forks.
199,843 after the default (36.8%)Credentials whose repository date is after 29 February 2024.That they got past the block. Dates can only err late, 51.8% of the live set is in shapes it does not block, and the post does not cross the two.
51.8% in unblocked shapesA coverage fact that matches GitHub's pattern documentation for generic patterns and Google API keys.An itemised count. The named categories total about 18% of the set (derived); the rest is not shown.
784 days medianThe median gap between a repository date and the crawl (derived, see the next section).How long a credential was valid (add 354 days), or how long its repository was public.
53% fall against 7%Credentials per million files in covered shapes fell 53%, against 7% in uncovered shapes, over twelve months either side of March 2024.A proven cause. Truffle itself lists a staged rollout, partly treated controls and providers moving to short-lived credentials.
Nobody revoked them (the post's title)Everything counted is, by construction, still live.A revocation rate, or that any owner was told. The post does not describe notification.

How old is a credential here? Probably older than its date says

Truffle dates each credential by the last modification of the file that holds it, which it calls the only per-file clock the corpus offers. The dataset card describes the same field as file modification time, "only as accurate as the GitHub metadata". The crawl downloaded one snapshot tarball per default branch. Git stores no per-file modification times, and its own documentation says archive entries take the committer time of the commit unless told otherwise. So we looked at what the dataset page shows.

The dataset card's viewer displays ten repositories. For eight it shows every file with its timestamp, and six of those eight have more than one file, from 2 to 34. In all six, every file carries the same timestamp, to the second: 17 files in one repository, 34 in another, 7 in a third. The 34-file repository is stamped 19 October 2021, 19:17:41 UTC, throughout. Two different repositories in the viewer show the same stamp, 23 October 2016, 19:36:36 UTC.

That is what a commit time looks like, not what a set of per-file edit dates looks like. Our inference, which the post neither makes nor rules out, is that the "leak date" is the date of the repository's last commit before the crawl, the same for every file in it. We checked ten repositories on one page, not the corpus, and Truffle can settle it in a sentence. If the inference is right, three things follow. A credential can only be older than its date, never younger, because a repository cannot have a last commit earlier than the secret it contains. So 63.2 per cent "before the default" is a floor and 36.8 per cent "after" is a ceiling, which is the direction Truffle says its error runs. A repository that leaked a key in 2018 and took one commit in 2025 is dated 2025, so the yearly density line and the before and after buckets record when repositories were last touched. And the median age describes repositories left alone.

The age arithmetic has a second problem that does not depend on that inference. The post's chart says ages run to "the day it was verified", 27 and 28 July 2026. The numbers do not fit that. The post's own era counts put 63.2 per cent of the credentials before 29 February 2024 (derived), so the median credential must be dated before that. But 784 days before 27 July 2026 is 3 June 2024. Counting back from the crawl date, 7 August 2025, gives 15 June 2023, which fits, and so does the post's yearly chart, which puts 60.3 per cent in 2023 or earlier (derived). The oldest credential, dated 13 June 2009, is 16.1 years before the crawl and 17.1 years before the test; the post says 16.1. The 90th percentile of 6.3 years fits the crawl date too, by the yearly counts. The ages appear to end at the crawl, not the test.

So, on that reading, 784 days is how far before the crawl the typical credential's date falls, and the credential was still working 354 days after the crawl on top of that: about 1,138 days, or 3.1 years (derived). Neither figure says how long the repository was public. A private repository made public in 2025 carries its old date.

Push protection is a pattern list with an off switch

The friendly names do a lot of work in this story. "Secret scanning" and "push protection" sound like a wall around secrets. GitHub's documentation describes something narrower, and Truffle's report agrees with it.

What the labels suggest and what GitHub's own documentation and announcements say, read on 30 September 2026.

LabelWhat it suggestsWhat the documentation says
Push protectionSecrets cannot be pushed.Blocks pushes that match supported patterns. The pusher can bypass it or switch it off in their user settings, and a user-level bypass raises no alert unless the repository has the feature on too.
Generic patternsAll credentials are covered.Private keys and database connection strings are generic patterns: push protection is not on by default for them, though it can be switched on.
Google API keysGoogle keys are covered.GitHub's pattern table marks google_api_key and google_gemini_api_key as not push protected. One prefix serves public Maps keys and billable Gemini keys.
Legacy tokensEvery token version is covered.GitHub says push protection supports only the most recent token versions it can identify with confidence.
Partner programmeLeaked tokens are revoked.GitHub forwards a match to the issuer. Revocation is a step the provider implements, and GitHub says how is up to the provider.

Truffle's strongest finding runs the other way, and it deserves its credit. Comparing twelve months either side of March 2024, credentials per million files in the six families GitHub blocks fell 53 per cent, against 7 per cent in six families it does not. The median family fell 57 per cent against 15 per cent, and the same comparison at earlier cut-off dates gives a difference of roughly zero. Truffle lists its own cautions. The separation is a ramp from March to July 2024 rather than a step, which fits GitHub's statement that the change might take a week or two to reach an account. Some of the control group was partly treated, because generic patterns can be switched on, which makes 53 per cent a floor on the effect. And AWS and Google pushed short-lived credentials over the same years, which could move these families without any help from GitHub. Truffle argues the timing across six unrelated providers counts against that, and cannot rule it out.

Both things hold together. The block roughly halves how often the secret shapes it covers reach public code. It does nothing for a credential already there, and 51.8 per cent of the live set is in a shape it does not block by default. The label covers only the first clause.

What keeps a credential alive is whether the issuer revokes it

Truffle's second finding is that survival depends on who issued the credential. Within its candidate cohort it compared, family by family, how many credentials were committed and how many still worked. The spread runs from 88.3 per cent for Postgres connection strings to 0.001 per cent for npm tokens.

Thirteen bars to scale show the share of committed credentials still live in July 2026: Postgres URIs 88.3 per cent, MySQL 74.6, Google Cloud service accounts 54.4, SendGrid 40.3, Docker Hub 32.8, AWS 8.3, Stripe 3.6, Redis 2.9, Slack 2.2, GitLab 0.64, GitHub 0.36, Hugging Face 0.05, npm 0.001. Colour shows whether default push protection covers the family. Footnotes flag test fixtures.
Drawn from the counts in Truffle Security's post of 29 September 2026. Percentages are our division.

Two of those bars mislead unless read with the post's own method note. November 2023 alone holds 105,104 Stripe keys and 100,752 npm tokens, which the post describes as test-fixture dumps with almost none live. Set against the survival list's totals, that is 84.7 per cent of the committed Stripe keys and 98.9 per cent of the committed npm tokens (derived, assuming both lists count the same unit). So the npm ratio mostly measures one fixture dump, and the Stripe 3.6 per cent is the same artefact: in the years 2019 to 2025 outside 2023, the post's chart data give 3,363 live of 8,197 committed, about 41 per cent (derived). The npm direction still holds, with no live tokens in about 750 committed outside 2023, but the headline ratio carries far less weight than it appears to.

The post leaves MongoDB out of every rate on purpose. Its detector reports a connection string only after connecting, so a dead one never enters the data, and a 100 per cent survival figure would be an artefact of the method. All 51,067 MongoDB strings in the live set are therefore live by construction.

The largest block of live credentials is Google Cloud service-account keys: 69,041 of 126,963 committed, or 12.7 per cent of the whole count (derived). The post's per-year data show those dated 2019 to 2023 surviving at 57 to 70 per cent and those dated 2025 at about 8 per cent. If time alone were at work the younger ones would survive more, so in our reading something else changed. The post does not say what.

GitHub finds, and the issuer decides. Where an issuer built the pipeline that takes a leaked token and kills it, Truffle finds almost nothing survives (its examples are GitHub and npm tokens). Where nobody is on the other end of the feed, a connection string lives until its owner rotates it. The post's own summary is that push protection "stops secrets at the door" and has nothing to say about what is already inside.

A count of survivors is not a count of leaks

The post's title says nobody revoked them. For the credentials counted, that is true by definition: a revoked credential fails the test and is not in the 543,699. The post cannot say how many were revoked, and it does not describe telling any owner or provider about these credentials; BleepingComputer's report does not either. The figure measures survival at one moment, not a failure to respond.

The same caution applies to the rising line in the post, from 3.72 live credentials per million files dated 2014 to 11.62 for files dated 2025, which it labels leak density. It counts survivors, so older cohorts have had longer to be revoked or to expire, and the x axis is the repository date discussed above. The line does not rise every year (5.83 in 2018 after 6.29 in 2017, and 10.40 in 2024 after 11.09 in 2023, from the post's chart data). Read it as live credentials per million files by repository date, not as how often developers leak. BleepingComputer gives 2015 as the starting year; the post says 2014. The comparison with Hugging Face, 221,303 against 543,699, sets two different corpora side by side. It says how much each corpus held, not which platform leaks more.

Method, interest and what the post does not reconcile

Truffle Security makes and sells secret-scanning software: its site lists TruffleHog in open-source and enterprise editions and an Analyze product, and the post advises scanning your own history. GitHub has its own interest: push protection on public repositories is free, while GitHub Secret Protection, a separately enabled product, covers private and internal repositories. The post reports a control working where it applies, which does not flatter the seller, and it publishes its own caveats in the method section. That deserves credit. The faults lie in the dating and in a few figures that do not add up.

Figures in Truffle Security's post that we could not reconcile, checked against its own text and the dataset card.

ItemStatedNot reconciled
Files scannedThe post: 58,467,468,698 file entries. The dataset card: 43.9 billion files, including stubs.The post does not explain the gap. On the card's figure the overall density would be 12.4 per million files, not 9.3 (derived).
MongoDB strings51,067 in the live set; 86,377 in the corpus, every one verified.Probably unique values against occurrences, but the post does not say.
Google API keys33,343 live Google API keys in one place, 31,374 live Gemini keys in another.The difference of 1,969 is not explained.
Unblocked shapes51.8% of the live set, about 281,600 credentials (derived).The named categories (MongoDB, Google API keys, Postgres, MySQL) total 97,681, or 18.0%. The other 183,955 are not itemised, and private keys are described as unverifiable.

What to do, in the order worth doing

Take this with you

For teams that commit code to any public repository, and for those that think a block at push time covers them

  • Treat any credential that has ever been in a public repository, fork or package as burned, whether or not anything flagged it. Revoke and replace it first, then clean the repository. GitHub's own guidance is that a secret stays in history after removal, so deleting it is not enough.
  • Find out which of your credentials are in public code now. Search your organisation's repositories and forks, and the personal and old repositories of current and former staff, including history and other branches, with a scanner that checks each hit against the issuer.
  • Put a clock on alerts. Measure the days from any secret scanning alert to the credential ceasing to work, give it an owner, and report it. An alert without a rotation changes nothing.
  • List your credential types against the gaps. Connection strings, private keys and generic API keys are not blocked by default, so assume no provider will revoke them for you. Ask each provider whether it takes GitHub's partner feed and revokes automatically.
  • Turn on what is off for your own repositories: push protection and secret scanning at repository and organisation level (GitHub says repository-level push protection requires GitHub Secret Protection), the generic patterns, and delegated bypass so that overriding a block needs a second person.
  • Scan before the push as well as at it. A pre-commit hook and a server-side or pipeline scan using the same detectors catch shapes and bypasses the default block does not.
  • Stop issuing keys that live for ever. Prefer short-lived credentials and workload identity, set expiry on what remains, and review which APIs are enabled on Google Cloud projects that hold public keys, because Truffle's February 2026 post showed Maps-era keys gaining Gemini access.
  • When you find an exposed credential, look back. Check the issuer's logs for use from unfamiliar sources between the leak date and the rotation, because rotation ends the exposure and does not show whether anyone used it.
  • Fix your test fixtures. Use placeholders that do not match a provider's real token format, so that scanners and reviewers are not trained to wave through a bypass marked as used in tests.

The question that exposes the gap

GitHub's block stops a recognised secret at the door, and Truffle's comparison says it works there, with the caveats above. Whether a credential was still live in July was settled after the door: whether anyone noticed, and whether an issuer at the other end of the feed turned the key off. Related briefings cover what ends up in public repositories (Glow's 13,000 public screenshots and the AI commit secret leak baseline) and what a pattern matcher cannot match (OpenAI's model split a GitHub token to avoid scanners).

So the question for any team is not whether push protection is on. It is this: when a credential of yours lands in a public repository, in a shape the block ignores, at an issuer that does not revoke, who finds out, after how many days, and who owns that number?

Key facts

Sources

  1. PrimaryGitHub Repos Exposed 543,699 Credentials. Nobody Revoked Them, 29 September 2026. The research report: corpus, method, every count, the three dating eras, survival by family and the push protection comparison. Read in full, including the data embedded in its interactive charts.Truffle Security Co.accessed 2026-09-30
  2. PrimaryThe Stack v3 dataset card: crawl method, 7 August 2025 cutoff, default branch only, no git history, forks with at least five stars, 224M repositories, 43.9 billion files, the file_timestamp field and the sample rows.Hugging Face (HuggingFaceCode)accessed 2026-09-30
  3. PrimaryKeeping secrets out of public repositories, 29 February 2024. Push protection rollout by default for pushes to public repositories, the bypass and disable options, and the week or two to reach an account.GitHub Blogaccessed 2026-09-30
  4. PrimarySecret scanning alerts are now available (and free) for all public repositories, 28 February 2023. Used for the date that separates the first two eras.GitHub Blogaccessed 2026-09-30
  5. PrimarySupported secret scanning patterns, read 30 September 2026. Capabilities by category (generic patterns are not push protected by default) and the pattern table entries for Google API keys, Gemini keys and MongoDB Atlas strings.GitHub Docsaccessed 2026-09-30
  6. PrimaryAbout push protection, read 30 September 2026. User-level push protection on by default, what it blocks, bypass reasons and alert behaviour.GitHub Docsaccessed 2026-09-30
  7. PrimarySecret scanning partner program, read 30 September 2026. How matches are sent to the issuing provider and what the page says about revocation.GitHub Docsaccessed 2026-09-30
  8. PrimarySecret leakage risks, read 30 September 2026. Secrets persist in git history after removal and must be revoked and replaced.GitHub Docsaccessed 2026-09-30
  9. Primarygit-archive documentation. The --mtime option: without it the committer time is used for archive entries. Used to interpret the dataset's file timestamps.Gitaccessed 2026-09-30
  10. PrimaryTruffleHog README. Describes validation as logging in to confirm whether a secret is live.Truffle Security Co. (GitHub)accessed 2026-09-30
  11. PrimaryScanning 7.6 Petabytes of Hugging Face Training Data for Secrets, 1 June 2026. Source of the 221,303 comparison and of Truffle's statement of what its checks did and did not do in that scan.Truffle Security Co.accessed 2026-09-30
  12. PrimaryGoogle API Keys Weren't Secrets. But then Gemini Changed the Rules, 25 February 2026. Background on keys deployed for public services gaining Gemini access.Truffle Security Co.accessed 2026-09-30
  13. Reported byOver 543,000 valid credentials exposed in public GitHub repositories, Bill Toulas, 30 September 2026. News coverage used as a pointer to the report and for its closing caveat that the findings do not show exploitation.BleepingComputeraccessed 2026-09-30
  14. Reported byOur earlier briefing on Glow's count of public screenshots on GitHub, linked rather than repeated.P.K. Sharmaaccessed 2026-09-30
  15. Reported byOur earlier briefing on the AI commit secret leak baseline, linked rather than repeated.P.K. Sharmaaccessed 2026-09-30
  16. Reported byOur earlier briefing on an OpenAI model splitting a GitHub token to avoid scanners, linked rather than repeated.P.K. Sharmaaccessed 2026-09-30

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

How often

Every new briefing in one email, at 7am, or at 7am, 12:30pm and 6pm. Nothing is sent when nothing is new. Unsubscribe any time.