Back to Blog
Insights

Git Hash Chain Malleability: A "Verified" Commit Isn't Unique

Git Hash Chain Malleability: A "Verified" Commit Isn't Unique

Most teams treat a signed, "Verified" commit on GitHub as a fixed point of trust: the same logical change will always hash to the same value, and that hash is what CI pipelines pin to, what dependency managers lock to, and what incident responders block or revert by. New research shows that assumption doesn't hold. An attacker who never touches your signing key can produce a second, byte-different commit (same files, same author, same message, a valid signature, and its own independent "Verified" badge) with a different commit hash. Here's what "hash chain malleability" actually means and why it matters.

What Hash Chain Malleability Actually Means

The finding comes from a preprint published July 2, 2026 by Jacob Ginesin at Carnegie Mellon University, titled "Git Hash Chain Malleability". The core claim: given any signed Git commit, an attacker without the signing key (and without breaking SHA-2) can construct a second, distinct commit with an identical tree, identical metadata, a valid signature, and a GitHub "Verified" badge, differing only in its commit hash.

Because every commit in a Git history references its parent by hash, a single malleated commit cascades forward: every descendant commit's hash changes too. That cascade is what the paper calls hash chain malleability: it isn't one broken commit, it's the whole chain built on top of it becoming ambiguous.

Three Ways to Malleate a Signature Without the Key

This isn't a broken hash function or a stolen private key. It's signature malleability: the fact that more than one valid byte-encoding can exist for the same underlying signature. The paper describes three distinct routes:

  • ECDSA algebraic inversion: converting a signature's (r, s) pair to (r, n-s). Both are mathematically valid signatures for the same key and message, but they produce different signature bytes.
  • RSA and EdDSA subpacket insertion: appending a well-formed but otherwise-ignored subpacket into the unhashed region of the OpenPGP signature packet, as permitted by RFC 4880. The signature still verifies; its byte representation changes.
  • S/MIME non-canonical re-encoding: re-encoding a DER (Distinguished Encoding Rules) length field inside the CMS (Cryptographic Message Syntax) envelope into a non-canonical form that's invalid strict DER but still valid BER (Basic Encoding Rules), which most parsers accept.

Two of these three routes (the ECDSA inversion and the OpenPGP subpacket insertion) reportedly also pass local git verify-commit checks, not just GitHub's server-side verification. That matters: it means this isn't a GitHub display quirk layered on top of otherwise-sound cryptography. The ambiguity exists in how commit signatures are represented and checked at the protocol level, and GitHub simply doesn't add any canonicalization on top of it before showing a badge.

Why GitHub Still Shows "Verified"

The paper's stated reason all three routes succeed on GitHub specifically: GitHub does not canonicalize the signature container before verifying it. It checks whether the signature is cryptographically valid for the given content, and if so, issues a "Verified" badge keyed to that commit's own hash, without checking whether an equivalent, differently-encoded signature already exists for the same logical change under a different hash. Each malleated variant gets treated as its own fully independent, fully verified commit.

What Actually Breaks

The paper frames the impact around anything that treats a commit hash as a stable, content-addressable identifier for security purposes, which is most of modern software supply-chain tooling:

  • Dependency and Action pinning. Pinning a GitHub Action or package to a specific commit SHA is standard supply-chain-security advice, specifically because tags can be moved but a commit hash supposedly can't be forged. This research shows that guarantee is weaker than assumed.
  • Reproducible-build systems (the paper names Nixpkgs and Go modules as examples) that use a commit hash as the primary key for content addressing.
  • Hash-based commit blocking and incident response: denylisting or reverting "the malicious commit" by its hash is less reliable if a second, equally verified hash exists for functionally the same change.

As of this writing, no CVE has been assigned, and neither GitHub nor other major Git forges have publicly announced a fix or canonicalization change in response. Treat this as an open finding to plan around, not a patched issue.

What To Do About It

  • Don't rely on a commit hash alone as proof that a change is unique or hasn't been tampered with: pair it with tree/content verification, not just the hash.
  • For anything pinned by commit SHA (Actions, dependencies, base images), keep an independent record of what that commit's actual contents were at pin time, not just the hash.
  • Treat "Verified" as evidence the signature is cryptographically valid for that specific commit object, not as proof that it's the only valid representation of that change.
  • If your incident response process blocks or reverts by commit hash, confirm your tooling also checks tree contents, not hash equality alone.
  • Keep an eye on GitHub's and other forges' guidance here: this is unresolved research, not a settled, patched vulnerability.

If your CI/CD pipeline, release process, or dependency management leans on commit-hash pinning as a security control, it's worth a second look at what would actually happen if that assumption broke. Our DevSecOps work covers exactly this: signed builds, provenance, and pipeline security that doesn't take a single control at face value. If you'd rather have us walk through your specific setup, get in touch.

Frequently Asked Questions

What is Git hash chain malleability?

It's research showing that a signed Git commit's hash isn't a unique fingerprint for that logical change. An attacker without the signing key can produce a second, differently-encoded but equally valid signed commit (same files, same metadata, a valid "Verified" badge) under a different hash, and because commits chain by hash, that difference cascades to every commit built on top of it.

Does this mean someone stole a private signing key?

No. The signing key is never compromised and the underlying cryptography (ECDSA, RSA, EdDSA, or S/MIME signatures) is not broken. The issue is signature malleability (multiple valid byte-encodings can exist for the same signature) combined with GitHub not canonicalizing the signature before verifying it.

Does this pass GitHub's verification only, or Git's own verification too?

Two of the three described techniques (ECDSA algebraic inversion and OpenPGP subpacket insertion) reportedly also pass a local git verify-commit check, not just GitHub's server-side check. All three earn an independent "Verified" badge on GitHub.

What's actually at risk from this?

Anything that treats a commit hash as a unique, tamper-evident identifier: pinning GitHub Actions or dependencies to a specific commit SHA, reproducible-build systems that use commit hashes as content-addressable keys, and incident-response processes that block or revert by hash.

Has GitHub fixed this or assigned a CVE?

Not as of this writing. No CVE has been assigned, and no forge has publicly announced a fix. This is an open research finding, not a patched vulnerability. Treat your pinning and verification practices accordingly rather than waiting on a fix.

Get Started

Want a security-first build?

Get a free security review. We'll look at where you stand today and tell you what to fix first, no strings attached.

Talk to an Expert
Git Hash Chain Malleability: A "Verified" Commit Isn't Unique - IKZERO