The ‘Verified’ Badge You Trust May Be Fooling You
That little green “Verified” badge next to a GitHub commit? It’s supposed to mean the code came from a specific person and hasn’t been tampered with. New research shatters that assumption.
A security researcher has demonstrated that a signed Git commit’s hash — the unique fingerprint that identifies every commit — is not the one-of-a-kind name the software world assumes. Given any signed commit, someone without access to the signing key can mint a second commit with the same files, same author, same timestamp, and a valid signature. GitHub still stamps it “Verified.”
Everything a reviewer would check matches. The commit’s hash does not. And that matters a lot.
How the Attack Works: Colliding Commit Hashes
Git relies on SHA-1 hashes to uniquely identify each commit. The hash is computed from the commit’s contents: the tree (file structure), parent commits, author, date, and message. When you sign a commit with GPG or SSH, Git signs that hash.
Here’s the catch: the signature covers the hash, but the hash itself isn’t bound to the commit data in a cryptographically tamper-proof way. An attacker can craft a second commit that produces the same hash — a collision — with entirely different content. Because the signature validates the hash, not the content, the signature remains valid.
The researcher demonstrated this by taking a legitimate signed commit and creating a new commit with a completely different tree (different files, different code) that produces the exact same SHA-1 hash. The signature from the original commit still verifies. GitHub’s interface shows “Verified.” A human reviewing the commit sees a green checkmark and moves on.
What the Attacker Can (and Cannot) Do
This isn’t a theoretical paper exercise. The researcher published a working proof-of-concept tool. Here’s what the attack enables:
- Swap code silently: An attacker can replace the files in a signed commit with malicious code while keeping the signature valid.
- Impersonate trusted developers: If you’ve ever signed a commit, someone could take that signature and attach it to a different commit that looks like it came from you.
- Bypass code review: A reviewer checks the signature badge, sees “Verified,” and approves the pull request. The actual code could be anything.
But there are limits. The attacker cannot change the commit author, date, or message — those are part of the hash computation. They can only swap the tree (the actual file contents). For many supply-chain attacks, that’s more than enough.
Why GitHub’s ‘Verified’ Badge Is Misleading
GitHub’s interface treats a valid signature as proof of integrity. The badge says “This commit was signed with a verified signature.” Most developers interpret that as: “This code is exactly what the author wrote and hasn’t been modified.”
That interpretation is wrong. The signature proves the hash is authentic. It does not prove the commit’s content matches what was signed. Git itself has no mechanism to bind the signature to the full commit data — only to the hash.
The researcher reported the issue to GitHub’s security team. GitHub acknowledged the behavior but classified it as working as designed, not a security vulnerability. The company noted that the attack requires an attacker to already have write access to the repository, and that repository administrators can enforce signed-commit requirements. But those mitigations don’t address the core problem: the signature badge is misleading.
What This Means for Software Supply Chain Security
This flaw matters most in automated supply-chain pipelines. Tools like Dependabot and Renovate check commit signatures as part of their trust model. A bot sees “Verified” and merges. An attacker with write access could inject malicious code through a signed commit that looks legitimate.
The same applies to CI/CD systems that validate signatures before deploying. If your pipeline trusts “Verified” as proof of integrity, you’re vulnerable.
How to Protect Yourself (Without Waiting for GitHub)
GitHub isn’t likely to change this behavior soon. In the meantime, here’s what you can do:
- Don’t rely on the badge alone: Verify the actual commit content. Use
git log --show-signature and compare the hash with the commit data.
- Use signed tags instead of signed commits: Tags sign the full commit object, not just the hash. This attack doesn’t work against signed tags.
- Pin exact commit hashes: In your dependency files, pin to specific commit hashes, not branches or tags. Verify the hash matches the expected content.
- Audit your supply chain: Review which commits are signed and by whom. Look for commits with valid signatures but unexpected content.
- Consider GitHub’s artifact attestations: GitHub’s newer attestation system binds signatures to the full repository state, not just the commit hash.
The green badge is convenient. It’s also a false sense of security. The hash is not the content, and a valid signature on a hash is not a valid signature on the code. Until Git or GitHub changes how signatures work, the “Verified” badge means less than you think.