HackproofHacks
Research 11 min read

GitHub Token Leak Risks Python's Repositories: What Happened and Why It Mattered

A leaked GitHub token with admin access to Python, PyPI and the PSF was found in a public Docker image. Here is how it happened and what it teaches about secret leaks.

Hassan Ansari

Hassan Ansari

· Updated Jul 22, 2026
A research card showing a leaked GitHub token buried inside a compiled Python file in a public container

GitHub Token Leak Risks Python’s Repositories

Every so often the security world gets a glimpse of a disaster that almost happened. Not an attack that succeeded, but a door left open that, had the wrong person found it first, could have poisoned software used by millions. The leaked GitHub token that granted administrative access to Python’s core repositories was exactly that kind of near miss, and it is worth understanding in detail, because the mistake behind it is one that ordinary developers make every single day.

Let me walk through what happened, why it was so dangerous, and the very practical lessons it leaves behind.

What was found

Security researchers, doing the routine but valuable work of scanning publicly available data for exposed secrets, discovered a GitHub personal access token that should never have been public. This was not a low-privilege key for some minor project. The token carried administrative access to the repositories behind Python itself, the Python Package Index known as PyPI, and the Python Software Foundation, the organisation that stewards the language.

To put that in perspective, those repositories sit at the very heart of one of the most widely used programming ecosystems on the planet. Python runs everything from small scripts to enormous production systems, and PyPI is the warehouse from which developers everywhere pull the packages their software depends on. A token with admin rights over that infrastructure is close to a master key.

The token belonged to a lead maintainer, and it had leaked not through some sophisticated breach but through a simple, human accident. It had been baked into a public Docker container image, freely downloadable by anyone. That is the part that should make every developer pause, because publishing a container with a secret inside it is an astonishingly easy mistake to make.

The clever part: it was hiding in plain sight

Here is the detail that makes this incident genuinely instructive rather than just alarming. The token was not sitting in obvious plain text in a source file, where a basic scanner would trip over it. It was buried inside a compiled Python file, a .pyc file.

When Python runs, it often compiles source code into bytecode and caches it in these .pyc files to speed things up. Most people, and crucially many automated secret scanners, treat these compiled artifacts as opaque and never look inside them. The assumption is that secrets live in source code, configuration, and environment files, so those are where scanning tools focus.

The researchers did not make that assumption. By inspecting the compiled bytecode, they recovered a credential that a simple text search of the source would have completely missed. This is the lesson within the lesson. Secrets do not only live where you expect them. They get compiled into bytecode, layered into container images, and committed deep into git history, and any of those hiding places can be recovered by someone who bothers to look. Scanning only your current source code gives you a false sense of safety.

Why this could have been a catastrophe

To understand the severity, you have to understand the concept of a software supply chain attack, because that is precisely what this token could have enabled.

Most attacks go after a single target directly. A supply chain attack is far more devastating because it strikes at the source. Instead of breaking into one organisation, the attacker poisons a widely trusted piece of software, a library, a package, an update, and then every organisation that installs that software downstream becomes a victim automatically. The malicious code rides in on the back of something people already trust.

Now apply that to Python and PyPI. With administrative access to those repositories, a malicious actor could, in principle, have tampered with code that flows out to millions of developers and the systems they build. Imagine a subtle backdoor inserted into a core component, or a compromised package that gets pulled into countless projects during a routine dependency install. Because the ecosystem is trusted implicitly and used almost everywhere, the blast radius would have been enormous and very hard to trace back to the source.

We have seen the pattern before in other ecosystems, where a single compromised dependency cascaded into thousands of downstream victims. The Python case had the potential to dwarf those, simply because of the scale at which Python and PyPI operate. It is not hyperbole to say this token was one of the more dangerous secrets ever accidentally exposed.

The good news, and why it stayed a near miss

The reason this story is a lesson rather than a headline about a global breach comes down to how it was discovered and handled. The researchers who found the token did the right thing. They reported it responsibly to the maintainers rather than exploiting it, and the credential was revoked within hours of being reported.

That quick revocation slammed the door before any attacker is known to have walked through it. There is no evidence the token was abused maliciously in the wild. It was found by people looking to help, disclosed quietly, and neutralised fast. This is responsible disclosure working exactly as it should, and it is worth appreciating the difference between a vulnerability found by a defender and the same vulnerability found by an attacker. The token was the same either way. The outcome was night and day.

It also prompted a healthy review of how such powerful credentials are managed, which is the kind of improvement that only tends to happen after a good scare.

How researchers find secrets like this

It is worth understanding how a leaked credential gets discovered in the first place, because the same techniques the good researchers use are exactly what criminals use, and knowing them changes how carefully you handle your own secrets.

Secret hunting starts from a simple premise. Developers leak credentials constantly, in public code, in commit history, in configuration files, and in published artifacts like container images and application packages. So researchers, and attackers, systematically scan these public sources looking for patterns that match known credential formats. A GitHub token, an API key, a cloud access key, each tends to have a recognisable shape, and automated scanners sweep enormous volumes of public data flagging anything that matches.

The naive version of this only looks at obvious text, which is why the Python token was interesting. It was not in obvious text. It was compiled into bytecode inside a container, a place most casual scanning never reaches. The researchers who found it went further, inspecting compiled artifacts and container layers rather than just source files. That extra effort is precisely why they found something a lazier scan would have missed, and it is a reminder that determined searchers do not limit themselves to the easy places.

Here is the uncomfortable implication. If a defender found this by looking harder, an attacker running the same broader scans could have too. The tooling to hunt secrets across public code, git history, and container registries is widely available and constantly running. Every credential you expose, even briefly, even somewhere non-obvious, is being scanned for by someone. The window between a secret going public and it being discovered is often measured in minutes, not days.

Why supply chain attacks are the modern nightmare

The Python case is frightening specifically because of what a supply chain compromise can achieve, and it is worth sitting with that, because this class of attack has become one of the defining security problems of the era.

Traditional security thinking imagines a perimeter. You harden your own systems, watch your own doors, and keep attackers out. Supply chain attacks make a mockery of that model, because the malicious code arrives through the front door, invited, riding inside software you chose to install and trust. No firewall questions a dependency you asked for. No amount of hardening your own perimeter helps when the threat comes bundled into a legitimate update.

We have watched this pattern cause serious damage across the software world. A single compromised build system, a single poisoned package, a single malicious update pushed through a trusted channel, and thousands of downstream organisations inherit the compromise automatically, often without any way of knowing. The attacker does the work once and the ecosystem distributes the payload for them. That leverage is exactly why sophisticated attackers, including state-linked groups, invest so heavily in these techniques.

Now picture that leverage applied at the scale of Python and PyPI, which sit beneath a staggering amount of the world’s software. The token that leaked here was, in the wrong hands, a key to precisely that kind of leverage. It did not get used that way, and we should be grateful, but the near miss illustrates why the industry now treats the integrity of package ecosystems as critical infrastructure. Protecting the source of trusted software is protecting everyone downstream at once.

The lessons for everyone who writes code

You are probably not maintaining the Python language, but the mistake at the centre of this incident is one you can absolutely make on a smaller scale, and the defences are the same regardless of the stakes.

Never hard-code secrets. Tokens, API keys, and passwords should never be written directly into your code, configuration, or container images. The moment a secret is embedded in something you might publish, you are one careless push away from exposing it. Load secrets at runtime from environment variables or a dedicated secret manager instead, so they never live in the artifacts you distribute.

Remember where secrets hide. This is the sharp lesson of the .pyc file. Your source code is not the only place a credential can end up. Compiled files, container image layers, build logs, and your project’s entire git history can all retain a secret long after you think you removed it. Deleting a token from your latest commit does nothing if it still sits in the history, and scanning only your visible source misses the rest.

Scan everything, before you publish. Use secret detection tools, and point them not just at your current code but at your commit history and your build artifacts, including container images. Catching a leaked credential before it goes public is worth an enormous amount, because after publication you have to assume it is compromised forever.

Rotate and limit. Give credentials the least privilege they need rather than broad admin rights, so that a leak is contained rather than catastrophic. And rotate them regularly, so that even a secret that slips out quietly has a limited useful life for anyone who finds it.

The takeaway

The Python token leak is a near-perfect case study because everything about it is relatable. A busy maintainer, a convenient container image, a secret compiled somewhere they did not think to check, and a mistake that in another timeline could have rippled out to millions of systems. The only reason it did not is that defenders happened to find it first and everyone acted quickly.

It is also worth appreciating what did not happen, because the response is as instructive as the mistake. The moment the researchers reported the token, it was revoked quickly, and the maintainers took the incident as a prompt to review how such powerful credentials are handled rather than brushing it off. That is exactly the right reaction. Mistakes are inevitable in any project run by busy humans, and the measure of a team is not whether it ever slips, but how fast it responds when someone points out the slip. A credential revoked within hours of disclosure is a very different story from one that lingers for months while nobody acts.

The uncomfortable truth is that secrets leak constantly, in codebases large and small, and most of the time nobody with good intentions is scanning for them. Treat every credential as something that will eventually escape if you are careless with it, keep it out of anything you publish, and scan the places you would rather not think about. The distance between a routine mistake and a supply chain disaster is often just a matter of who finds the secret first.

#supply chain #python #pypi #secrets #github #vulnerability #security research
Free newsletter

Liked this? I write one like it every week.

One practical security lesson in your inbox each week, explained the same simple way. Join 10,000+ readers. Unsubscribe anytime.

From the article

Need a security assessment?

HackproofHacks provides web application and API penetration testing — using the same techniques covered in this article, with your explicit authorisation.

Book a free scoping call

More on Research.

All articles →
FAQ

Questions about this topic.

What exactly was leaked in the Python GitHub token incident?

Security researchers found a GitHub personal access token that had administrative access to the core repositories of Python, the Python Package Index known as PyPI, and the Python Software Foundation. The token belonged to a lead maintainer and had been accidentally exposed inside a public Docker container image, buried in a compiled Python bytecode file rather than sitting in obvious plain text.

How dangerous was the leaked token?

Extremely, in theory. Admin access to the repositories behind Python and PyPI could have let an attacker tamper with code that millions of developers and organisations pull in as dependencies. That is the ingredients of a massive software supply chain attack, where malicious code inserted at the source spreads automatically to everyone downstream. The saving grace was that it was found and revoked by researchers before any known malicious use.

How was the token found if it was hidden in a compiled file?

Researchers scanned publicly available artifacts, including Docker container images, for secrets. The token was not in obvious source code but inside a compiled Python bytecode file, a .pyc file, which many secret scanners overlook. By decompiling or inspecting those compiled files, the researchers recovered the credential that a simple text search would have missed. It shows that secrets hide in more places than people check.

What is a software supply chain attack?

It is an attack that compromises software at its source or distribution point so that the malicious code spreads to everyone who uses it downstream. Instead of attacking one target directly, the attacker poisons a widely used dependency, tool, or update, and every organisation that installs it becomes a victim. Because ecosystems like Python's PyPI are trusted and used everywhere, a successful attack there could reach an enormous number of systems at once.

How can developers avoid leaking secrets like this?

Never hard-code tokens or credentials into code, configuration, or container images. Use dedicated secret management, load secrets from environment variables or vaults at runtime, and scan your repositories and build artifacts with secret detection tools before publishing. Crucially, remember that compiled files, container layers, and git history all retain secrets, so scanning only your current source is not enough. Rotating credentials regularly limits the damage when something does slip through.

Was Python actually compromised by this leak?

No known malicious exploitation occurred. The token was discovered by security researchers, reported responsibly, and revoked within hours, closing the window before any attacker is known to have abused it. It was a serious near miss rather than an actual breach, and it prompted the maintainers to review how such credentials are handled. The lesson lives on even though the disaster did not happen.