ben.milleare
All notes
· security · leadership · infrastructure

GitHub got hacked

GitHub had 3,800 internal repos exfiltrated via a poisoned VS Code extension. If your private repos have ever held a secret, rotate it today.

Dimly lit concrete-walled room with a single bare incandescent bulb hanging from a long cord directly overhead. A man sits on a battered wooden chair beneath the bulb, hands resting on his thighs, wearing a fitted plain black t-shirt with 'GitHub' across the chest in bold white sans-serif letters. His head and face are covered by a plain beige canvas hood. Hard top-down chiaroscuro lighting from the bulb; deep shadows fall off into the corners of the room.

On the 19th of May, GitHub confirmed that an employee device had been compromised through a poisoned VS Code extension, and that roughly 3,800 internal repositories had been exfiltrated by a group calling itself TeamPCP, now apparently selling the haul jointly with LAPSUS$ for $95k or threatening to leak it for free if no buyer turns up. GitHub’s official line is that customer-side repositories were not touched, which is the only good news in this story.

The immediate work is the rotation; any secret that ever made it into a repository, deliberately or accidentally, gets cycled today and the old values audited for use. The durable lesson, though, is that the defence belongs much earlier in your git flow than the moment GitHub decides to have a bad day. A pre-commit hook running something like gitleaks or talisman is half a morning of setup and catches the obvious cases on the developer’s own machine; a CI pass with the same rules catches whatever escaped with --no-verify; and a code review culture trained to flag the unobvious turns the whole thing into defence in depth. The teams that already had all three running treated this week as a non-event.

And secrets aren’t the only thing worth surfacing. Half the founders I talk to have at some point pushed a .env to a “private” repo and then forgotten about it; the same casual posture leaks plenty that isn’t a key. Internal hostnames hardcoded for one bit of testing, URLs of admin endpoints that were never meant to be public, names and shapes of internal services, a comment that explains a workaround in just enough detail to point an attacker straight at it; none of it is catastrophic on a private repo while the platform is behaving itself, but all of it turns into reconnaissance gold the moment that trust boundary slips.

Most of that doesn’t belong in the repo in the first place. Config that varies between environments, the hostnames, endpoint URLs, third-party identifiers and tuning parameters that tend to get pasted into a YAML file because the alternative felt like ceremony, belongs in something like AWS SSM Parameter Store (or Google Secret Manager, Azure Key Vault or HashiCorp Vault depending on where you sit), pulled at deploy or runtime rather than committed alongside the code that uses it. The codebase stays generic, rotation becomes a config push rather than a code release, and the next time something does leak it embarrasses your secrets store instead of handing over a map of your services.

GitHub’s own availability reports have been admitting for months that the platform is straining under a load profile they didn’t design for, and this breach lands at the end of a long run of degradations rather than out of a clear sky. April’s report walks through it honestly: Copilot agent sessions queueing for nearly an hour, Actions falling over more or less weekly, a capacity plan that started at 10x last October and has already been redrawn for 30x to keep up with the agentic-development load profile that’s gone vertical since late 2025.

The same force pulling the platform apart on the load side is sharpening the attack side too. Exploit discovery used to be slow, expert work; it is now something an attentive operator runs continuously across thousands of repos with a coding agent and a checklist. The leaked GitHub-internal source code is exactly the sort of corpus that makes that kind of automated reconnaissance more effective, not less, and the asymmetry between attacker and defender is no longer tilted the way it used to be.

So treat this week as the nudge to do the unglamorous work. Rotate every secret your team can think of, run a tool like GitGuardian or TruffleHog over your history to find the ones they can’t, move the survivors into a proper secret manager, and wire up the pre-commit and CI gates that mean the next leak doesn’t depend on GitHub never having a bad day. Being defensive about what enters your codebase is the job, and nobody else will quietly do it for you.