Why a "Verified" GitHub Commit Hash Is Not Unique
Signature malleability allows attackers to alter verified commit hashes without breaking their cryptographic signatures or possessing private keys.
In modern DevSecOps, the commit hash is treated as an immutable, unique anchor of trust. We pin dependencies to specific hashes, lock down CI/CD pipelines with them, and write incident response playbooks to block or revert compromised commits by their hashes. The assumption is simple: a specific hash represents a specific, immutable state, and if it carries GitHub's green "Verified" badge, it is cryptographically tied to a trusted developer's private key.
That assumption is wrong.
New research by Jacob Ginesin of Carnegie Mellon University reveals that the "Verified" badge on GitHub does not guarantee a unique commit hash. An attacker without access to the signer's private key can take a validly signed commit and generate an entirely different commit hash that still carries a valid signature and displays as "Verified" on GitHub. This vulnerability, termed "hash chain malleability," breaks the 1:1 mapping between a signed state and its hash, introducing subtle but serious risks to supply-chain security.
The Mechanics of Signature Malleability
To understand how this works, we have to look at how Git signs commits. Git identifies every object by a hash of its contents. For a commit, this hash covers the tree (the directory state), the parent commit hashes, the author and committer metadata, the commit message, and the raw bytes of the signature itself. A raw commit object looks like this:
tree 920a67a31234567890abcdef1234567890abcdef
parent 4f1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b
author Jane Doe <jane@example.com> 1710000000 +0000
committer Jane Doe <jane@example.com> 1710000000 +0000
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
[Signature Bytes Here]
-----END PGP SIGNATURE-----
Commit message here
Crucially, this is not a hash collision attack. The research does not exploit weaknesses in SHA-1 or the ongoing migration to SHA-256. Instead, the vulnerability lies in signature malleability: the fact that a single logical commit can have multiple, byte-different but cryptographically valid signed serializations. Each of these serializations results in a different commit hash.
Ginesin's paper outlines three distinct routes to achieve this, covering every GPG-based signing scheme that GitHub verifies:
- ECDSA Symmetry: ECDSA signatures consist of two integers,
(r, s). Due to the algebraic symmetry of the elliptic curve, the signature(r, n-s)(wherenis the order of the curve) is mathematically just as valid as(r, s). An attacker can flip this value to produce a new signature payload, changing the commit hash while keeping the signature valid. - OpenPGP Unhashed Subpackets: For RSA and EdDSA, which do not share the ECDSA symmetry trick, the paper exploits the structure of OpenPGP packets. Under RFC 4880, an OpenPGP signature packet can contain an "unhashed" region for metadata. Because this region is explicitly not covered by the signature's mathematical hash, an attacker can append a well-formed but ignored subpacket to it. The signature remains valid, but the raw bytes of the commit change, yielding a new commit hash.
- S/MIME Length Re-encoding: For S/MIME signatures, the attack targets the Cryptographic Message Syntax (CMS) structure. By re-encoding a length field into a non-canonical form that violates strict Distinguished Encoding Rules (DER) but is still accepted by Basic Encoding Rules (BER), the attacker alters the byte representation of the signature container without altering its cryptographic validity.
The GitHub Factor: Persistent Verification
This signature malleability becomes a practical exploit because of how GitHub handles verification.
First, GitHub's server-side verification engine does not canonicalize signature containers before verifying them. It accepts the ECDSA inversion, the OpenPGP unhashed subpacket insertion, and the non-canonical S/MIME BER encoding. Because it accepts these mutated signatures as valid, it issues a "Verified" badge for the resulting mutated commit hash.
Second, GitHub employs a feature called "persistent commit signature verification." According to GitHub's documentation, when a signed commit is pushed and verified, GitHub stores a durable verification record keyed on the commit hash. This record is never re-verified or updated, even if the signing key is later revoked or expires. By generating a mutated commit hash, an attacker can force GitHub to create a new, permanent "Verified" record for the mutated hash.
Local Git tooling behaves slightly differently. While git verify-commit accepts the two OpenPGP routes, it rejects the non-canonical S/MIME encoding. GitHub, however, accepts all three.
The Supply-Chain Threat Model for Developers
What does this mean for your workflows? If the tree (the actual code) remains identical, why should a developer care?
The danger lies in how automated systems and security policies consume commit hashes.
- Hash Chain Malleability: Because Git commits are linked in a directed acyclic graph where each commit references its parent's hash, mutating a parent commit's hash forces a rewrite of all subsequent commits. If an attacker can mutate a parent commit while preserving its "Verified" status, they can cascade this change down the chain. This allows them to construct alternative, fully "Verified" histories of a repository.
- Evasion of Incident Response: If a security team detects a malicious or compromised commit, their immediate response is often to block or revert that specific commit hash. If an attacker can instantly generate a mutated version of that commit with a different hash that still shows as "Verified," they can bypass automated blocklists and automated security gates.
- Policy Engine Bypasses: Many enterprise CI/CD pipelines use policy engines to assert that only commits with specific, pre-approved hashes are deployed to production. If an attacker can present a mutated hash of a verified commit, they can cause desynchronization between the policy engine, the build cache, and the deployment target.
- The Fragility of Commit Signing: This vulnerability is compounded by the fact that commit signing adoption is already incredibly low. A 2025 empirical study published on arXiv analyzed 60 open-source repositories across security, databases, web development, and machine learning, finding that only about 10% of all commits were verified. When the few signed commits we do have can have their hashes mutated without losing their verified status, the entire trust model of commit signing is weakened.
Mitigating the Malleability Gap
To fix this, the burden falls primarily on code hosting platforms like GitHub. Forges must begin canonicalizing signature containers before verification. For example, stripping unhashed OpenPGP subpackets, enforcing strict DER encoding for S/MIME, and canonicalizing ECDSA signatures to a standard s value would prevent these mutated signatures from being accepted.
Until platforms implement these checks, developers and security engineers should:
- Avoid relying solely on commit hashes for cryptographic identity: A commit hash is an identifier of Git object state, not a unique cryptographic proof of signature identity.
- Verify signatures locally: When writing automated audit tools, use
git verify-commitor custom scripts that enforce strict canonicalization rather than relying blindly on API responses or badges from hosting platforms. - Enable Vigilant Mode: While GitHub's vigilant mode does not prevent signature malleability, it flags commits where the author identity does not match the signing key, reducing the surface area for impersonation.
Sources & further reading
- New Research: A "Verified" GitHub Commit Is NOT Unique — internationalcyberdigest.com
- About commit signature verification - GitHub Docs — docs.github.com
- Commits are signed as Unverified, what am I supposed to do? · community · Discussion #153997 — github.com
- On the Prevalence and Usage of Commit Signing on GitHub — arxiv.org
- git - unverified commits in GitHub - Stack Overflow — stackoverflow.com
Ji-ho covers the increasingly tangled overlap between cloud architecture and security, drawing on a background as a penetration tester to keep his reporting grounded in real-world attack paths. He never lets a vendor claim go unquestioned and insists that every buzzword come with a proof of concept.
Discussion 0
No comments yet
Be the first to weigh in.