This is episode thirty-five of Git Good.
Right now, on your computer, you can open a terminal and type two commands. Set your name to Linus Torvalds. Set your email to his public address at the Linux Foundation. Your next commit will look exactly like it came from the creator of Git himself. There is no password prompt. No verification step. No challenge. Git will accept whatever you tell it, write those values into the commit object, and never ask a single question about whether you are who you claim to be.
This is not a bug. This is not an oversight that the Git team forgot to fix. This is how Git was designed from the very first day.
Linus Torvalds built Git in two thousand five for a specific community. The Linux kernel developers. A few hundred people, most of whom had met each other at conferences, exchanged PGP keys in person, and built trust through years of public mailing list participation. In that world, identity was social. You knew who someone was because you had seen their patches, read their arguments, watched them earn credibility over months and years. Cryptographic verification existed for the moments that truly mattered, like signing a release tag, but for the daily flow of patches and commits, social trust was enough.
That was twenty years ago. Today, over one hundred million developers use GitHub. The vast majority of them have never met each other. They collaborate across continents, across time zones, across organizational boundaries. The social trust model that worked for a tight-knit kernel community does not scale to a planet. And Git still has not changed. It still trusts whatever you type into those two lines. It still does not check.
Here is what a Git commit actually stores about its author. Two strings of plain text. A name and an email address. That is it. No cryptographic link to a real identity. No token from an identity provider. No proof of any kind. Just text, stored alongside the code changes, treated with exactly the same level of trust as a comment in a config file.
The implications are straightforward. Anyone can claim any identity in any commit. You can attribute your work to someone else. You can attribute someone else's work to yourself. You can create a commit history that looks like a famous developer contributed to your project when they never heard of it. You can backdate commits to make it look like code was written months before it actually was. Both the identity and the timestamp are whatever you say they are.
This is not theoretical. Security researchers have demonstrated it repeatedly. In two thousand twenty-two, a team published a detailed walkthrough showing how to spoof any user on GitHub. Set the name and email to match a target's GitHub profile. Push a commit to a repository where they are listed as a collaborator. GitHub's interface shows their profile picture, links to their account, and displays the commit as if they made it. The only visual difference is the absence of a small green "Verified" badge, a distinction that most developers have never thought about and many have never noticed.
A separate researcher built a tool called gitfraud that automates the entire process. Feed it a GitHub username, and it generates commits attributed to that person. The tool exists not as an attack but as a demonstration of how thin the identity layer really is. Or rather, how there is no identity layer at all.
Think about what this means for a supply chain. When a developer reviews a pull request, they see a name and a profile picture attached to each commit. They trust that the person who wrote the code is who the commit says they are. That trust is not verified by Git. It is not verified by GitHub, unless the commit is signed. It is simply assumed. And assumptions, in security, are the thing that gets you compromised.
The fix exists. It has existed for over a decade. Commit signing allows a developer to attach a cryptographic signature to every commit, proving that the code was written by someone who controls a specific key. GitHub displays a green "Verified" badge on signed commits. The technology works. The math is sound. The tooling is available on every platform. And almost nobody uses it.
A research team published a study in two thousand twenty-five at the International Conference on Evaluation and Assessment in Software Engineering. They analyzed sixty popular open source repositories on GitHub across four domains, spanning five years of commit history. The finding was stark. Only about ten percent of all commits were signed.
The breakdown by domain tells the story even more clearly. In security-focused repositories, where the developers presumably understand the threat model better than anyone, twenty-eight percent of commits were signed. Better, but still barely a quarter. In web development repositories, roughly thirteen percent. In database projects, about six percent. And in machine learning repositories, two and a half percent. The developers building the AI systems that millions of people rely on sign fewer than three out of every hundred commits.
The researchers found something else that was arguably worse. After GitHub launched its "Verified" badge and vigilant mode in two thousand twenty-one, there was a brief uptick in signed commits. Developers noticed the feature, tried it out, set up their keys. Then, after early two thousand twenty-three, the trend reversed. Signing rates declined. The initial curiosity faded, the friction remained, and developers went back to unsigned commits.
The reasons are not mysterious. Setting up GPG commit signing is a genuinely unpleasant experience. You need to generate a keypair, configure your Git installation to use it, potentially set up a GPG agent so you do not have to type your passphrase on every commit, upload the public key to GitHub, and remember to maintain the key when it expires. If you work on multiple machines, you need the key on all of them. If you lose the key, your old signatures become unverifiable. The whole process feels like punishment for trying to do the right thing.
In August two thousand twenty-two, GitHub added support for signing commits with SSH keys. This was genuinely simpler. Most developers already have SSH keys for authenticating with GitHub. Using the same key, or a different one, for signing requires a few lines of Git configuration instead of the GPG gauntlet. It was the right idea. But even with SSH signing, the adoption numbers tell you that "simpler" is not the same as "simple enough." When the default is unsigned, and signing requires any setup at all, most developers will never do it.
There is one project on earth that has solved the identity verification problem for Git. It is the same project that Git was built for in the first place.
The Linux kernel maintains a web of trust that has no equivalent anywhere else in open source. When a subsystem maintainer finishes a set of patches and wants Linus Torvalds to pull them into the mainline kernel, they do not just push a branch. They create a signed tag. That tag carries a cryptographic signature proving that the maintainer reviewed and approved every commit in that branch. When Linus pulls, he verifies the signature. If the signature does not match a key he trusts, the pull does not happen.
But a signature is only as good as the key behind it. The kernel community maintains a dedicated repository of developer public keys, hosted on kernel.org. To get your key into that repository, it must carry at least one signature from someone whose key is already there. And that person's key must be traceable, through a chain of signatures, back to Linus Torvalds himself. It is a web of trust in the original sense. Every new participant is vouched for by an existing participant, and the chain ultimately anchors to the person at the top.
Torvalds himself has described this philosophy. For him, the identity behind a key matters less than the history of what that key has done.
It is a history of behavior rather than a collection of key-signing parties that builds trust for me.
This system works. It has protected the kernel through decades of contributions from thousands of developers across dozens of countries. It is also extraordinarily expensive in human terms. Maintaining PGP keys, attending key-signing parties at conferences, managing the web of trust as developers join and leave, all of it requires sustained effort from people who would rather be writing code. The kernel can afford this overhead because the stakes justify it and because the community has institutional memory stretching back decades.
Almost no other project does anything like it. The barrier is not technical. The tools exist. The barrier is cultural and organizational. Most open source projects are maintained by one person, maybe two, working in their spare time. Asking them to also maintain a cryptographic web of trust is asking them to do a second unpaid job on top of their first unpaid job.
Everything we have talked about so far, the spoofable identity, the unsigned commits, the gap between what is possible and what anyone actually does, all of it converges in a single story. A story that shook the open source world in the spring of two thousand twenty-four and that the next episode of this series will explore in full detail. But to understand the supply chain attack, you first need to understand the identity failure that made it possible.
On October twenty-ninth, two thousand twenty-one, a developer using the name Jia Tan sent a small, harmless patch to the mailing list for a compression library called XZ Utils. The patch added an editor configuration file. Nothing controversial. Nothing suspicious. Just a helpful contribution from someone new.
A month later, another patch. A fix for a reproducible build issue. Useful, competent work. More patches followed through two thousand twenty-two. Each one small. Each one reviewed. Each one building a trail of commits that told a story. This person cares about this project. This person shows up. This person does the unglamorous work.
And then, in the summer of two thousand twenty-two, something else started happening on the XZ Utils mailing list. New voices appeared. A person calling themselves Jigar Kumar began posting complaints. The project was moving too slowly. The sole maintainer, Lasse Collin, was not keeping up. Patches were languishing. The project needed new leadership.
Progress will not happen until there is new maintainer. Patches spend years on this mailing list. There is no reason to think anything will change.
The messages were blunt and relentless. Another account, calling itself Dennis Ens, posted similar complaints. Both pushed the same message. Collin was overwhelmed. Collin needed help. Someone should take over.
Neither Jigar Kumar nor Dennis Ens existed. Their email addresses appear nowhere else on the internet. Not in any other mailing list archive. Not in any data breach dump. Not in any social media profile. They were sock puppets, manufactured identities whose sole purpose was to pressure a burned-out maintainer into handing over control. And it worked. By two thousand twenty-three, Jia Tan had become a co-maintainer of XZ Utils with full commit access.
In February and March of two thousand twenty-four, Jia Tan inserted a backdoor into XZ Utils. The compromised code made its way into release tarballs that shipped with major Linux distributions. It targeted the SSH authentication process. If it had gone undetected, it would have given the attacker remote access to any server running the affected version. The severity score was ten out of ten. The maximum.
The attack was caught by accident. A Microsoft engineer named Andres Freund was running performance benchmarks on PostgreSQL when he noticed that SSH logins were taking five hundred milliseconds instead of the usual hundred. He investigated. The trail led to the XZ library, to the backdoor, and to Jia Tan.
Freund posted his findings to the open source security mailing list on March twenty-ninth, two thousand twenty-four.
After observing a few odd symptoms around liblzma on Debian sid installations over the last weeks, logins with SSH taking a lot of CPU, valgrind errors, I figured out the answer. The upstream XZ repository and the XZ tarballs have been backdoored.
The open source world scrambled. Distributions pulled the affected packages. The backdoor was neutralized before it reached most production systems. But the margin was terrifyingly thin. A few more weeks, and the compromised version would have been in stable releases everywhere.
The next episode will tell the full technical story of the XZ attack. But the identity lesson is this. Git did not verify Jia Tan's identity. GitHub did not verify Jia Tan's identity. The mailing list did not verify Jia Tan's identity. The only verification that happened was social. Jia Tan sent good patches. Jia Tan showed up consistently. Jia Tan earned trust the same way every legitimate contributor earns trust, by doing the work. And that was enough. Because in Git's model, that is all there is.
There are two ways to think about Git's trust model, and both of them are correct.
The first says that the openness is a feature. Git was built for a world where anyone can contribute. No gatekeeper decides who gets to write code. No identity authority grants or revokes permission. You show up, you send a patch, and the quality of your work speaks for itself. This is the open source ideal. Judge the code, not the credential. The fact that a teenager in Bangladesh and a senior engineer at Google look exactly the same in a Git log is not a bug. It is the entire point.
The second says that the openness is an invitation to exploitation. When identity is free and unverified, impersonation is trivially easy. When trust is built through social reputation alone, social engineering is the obvious attack vector. The XZ incident did not exploit a flaw in Git's code. It exploited the space where Git's philosophy meets reality. The belief that social trust would scale the way technical trust does.
Both of these views are true simultaneously, and that is what makes the problem so hard. Tightening identity verification makes Git safer but also makes it less accessible. Requiring signed commits would stop impersonation but would also stop the teenager in Bangladesh who does not have a GPG key and does not know what one is. Every security measure is also a barrier to entry. And Git's entire history is a story of lowering barriers.
There is a project called Sigstore that represents the most promising attempt to thread this needle. Instead of asking developers to manage long-lived cryptographic keys, which is the thing that killed GPG adoption, Sigstore uses what it calls keyless signing. You authenticate with an identity provider you already use, Google, GitHub, or Microsoft. A short-lived certificate is created, valid for only minutes. Your artifact is signed, the signature is logged in a public transparency ledger, and the key is destroyed. No key to manage. No key to lose. No key to expire and break your verification chain.
The elegance of the approach is that it shifts the question from "do you have a key?" to "can you prove who you are?" The first question requires setup, maintenance, and expertise. The second requires logging into an account you already have. Sigstore is already widely adopted for signing container images and software packages. Applying the same model to Git commits would eliminate the friction that keeps ninety percent of developers from signing anything.
But it would also mean trusting identity providers. Your Git identity would be anchored to a Google account or a GitHub account or a Microsoft account. For the kernel community, where independence from any single corporation is a core value, that trade-off might be unacceptable. For the other hundred million developers who already log into GitHub every day, it might be exactly right.
The AI thread makes this even more complicated. When an AI coding assistant generates a commit, whose identity goes on it? The developer who prompted the AI? The AI provider? A bot account? If a signed commit means "I vouch for this code," what does it mean when the person signing it did not write the code and may not have read it carefully? The identity model was built for a world where people wrote code. In a world where machines write code and people review it, maybe review it, the meaning of identity in a commit is changing faster than the tools can keep up.
There is a gap in Git that has been there since two thousand five. On one side, you have a tool that stores identity as two lines of plain text, trusting whoever fills them in. On the other side, you have a world of one hundred million developers, automated pipelines, AI agents, and nation-state attackers. The gap between those two realities has been growing for twenty years, and it is not getting smaller.
The Linux kernel closed the gap with a web of trust that costs enormous human effort to maintain. GitHub tried to close it with "Verified" badges and vigilant mode, but the opt-in design means the gap persists for the ninety percent who never set up signing. Sigstore offers a path that might work for the majority, but it trades one kind of trust for another. And the XZ attack showed what happens when someone decides to walk through the gap deliberately, patiently, over the course of two and a half years, building exactly the kind of social trust that Git relies on.
Episode thirty-three told you about the secrets hiding in Git's history. Episode thirty-four told you about who gets blamed when something goes wrong. This episode is about a more fundamental question. When a commit says it was written by a certain person, should you believe it?
Right now, for most of the world's code, the honest answer is that you do not know. You trust. You assume. You look at the name and the profile picture and the history of contributions and you make a judgment. The same kind of judgment that the XZ Utils community made about a developer named Jia Tan, who showed up, did good work, earned trust, and then used that trust to plant a backdoor that almost broke the internet.
In the next episode, we will follow that backdoor from the moment it was planted to the moment it was found. The supply chain, the technical details, and the five hundred milliseconds that saved us. That is episode thirty-six. The Supply Chain.
That was episode thirty-five of Git Good.
Git log, show signature. Add that flag and your log output will include signature verification for every commit. Most of them will say "no signature." That is the point. The ones that do show a signature tell you that someone cared enough to set up signing and prove their identity cryptographically. In a world where anyone can claim any name in a commit, those green "Verified" badges are the closest thing Git has to proof. Whether that proof means anything depends on whether you trust the key, or the identity provider, or the web of trust behind it. But at least it is something. Which is more than the unsigned commits can say.