CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-25934
4.3

Broken Seals: How go-git Forgot to Check the Receipt (CVE-2026-25934)

Alon Barad
Alon Barad
Software Engineer

Feb 10, 2026·6 min read·9 visits

No Known Exploit

Executive Summary (TL;DR)

The `go-git` library, used extensively in the Go ecosystem for Git operations, failed to validate SHA-1 checksums when processing packfiles. This means an attacker (or a bad disk sector) could feed the library corrupted data, and `go-git` would happily commit it to your object database without raising an error. Fixed in v5.16.5.

A fundamental data integrity flaw in the popular `go-git` library allowed for the consumption of corrupted or malicious Git packfiles without detection. By failing to verify checksums in `.pack` and `.idx` files, the library broke the core promise of Git's content-addressable storage model.

The Hook: The Engine Under the Hood

If you are writing Go code and need to interact with a Git repository, you aren't going to exec.Command("git", ...) like a barbarian. You use go-git. It's the de facto standard, a pure Go implementation of the Git protocol. It powers everything from Kubernetes GitOps controllers (like Flux) to vulnerability scanners and CI/CD pipelines. It is the silent engine ensuring that the code you think you are deploying is the code you actually have.

But here is the thing about engines: we trust them to verify the fuel quality. Git, at its core, is a content-addressable filesystem. Everything is defined by its hash. If you change a single bit of a file, its hash changes, and the Git Merkle tree rejects it. It is the cryptographic guarantee that makes Git, well, Git.

CVE-2026-25934 is a story about what happens when that guarantee is implemented with a generic TODO where the security check should be. For versions prior to 5.16.5, go-git was essentially accepting packages from strangers without checking the seal. It turns out, reading the checksum at the end of a file and actually comparing it are two very different things.

The Flaw: A Missing Receipt Check

To understand the gravity of this screw-up, you have to understand the anatomy of a Git transfer. When you run git clone or git fetch, you aren't downloading individual files one by one. You are downloading a Packfile (.pack). This is a compressed stream of objects (commits, trees, blobs).

To keep things speedy, Git also uses an Index file (.idx) to map object IDs to their offsets within that massive packfile. Both of these formats—.pack and .idx—end with a 20-byte SHA-1 trailer. This trailer is the checksum of the entire file's content. It is the digital seal. The protocol dictates: read the data, hash it as you go, and when you hit the end, compare your calculated hash with the trailer.

The vulnerability in go-git was embarrassingly simple: it parsed the file, it read the objects, it may have even read the trailer bytes into a buffer... but it failed to validate that the data actually matched the checksum. It was the security equivalent of a bouncer looking at your ID, seeing it is written in Crayon, and letting you into the club anyway because he didn't feel like reading.

The Code: Silent Corruption

Let's look at the logic flow. In a proper implementation, the pseudo-code for reading a packfile looks something like this:

// The way it SHOULD be
func ReadPackfile(r io.Reader) error {
    hasher := sha1.New()
    tee := io.TeeReader(r, hasher)
    
    // Process objects from the stream
    processObjects(tee)
 
    // Read the 20-byte trailer from the stream
    expectedChecksum := make([]byte, 20)
    io.ReadFull(r, expectedChecksum)
 
    // The critical step go-git missed:
    calculatedChecksum := hasher.Sum(nil)
    if !bytes.Equal(calculatedChecksum, expectedChecksum) {
        return ErrIntegrityViolation
    }
    return nil
}

In the vulnerable versions of go-git, the logic effectively skipped the bytes.Equal check or the hashing process during specific ingest operations (like fetch or local .idx generation). The code would consume the stream, populate the internal object database, and return nil (success), even if the underlying bytes were garbled.

This isn't just a memory safety issue; it's a logic error that undermines the application's trust model. If your GitOps controller pulls a manifest, and the network corrupts a bit flipping replicas: 1 to replicas: 0 (unlikely but possible), or more maliciously, if an attacker injects a modified object stream, go-git wouldn't notice. The patch in v5.16.5 forces a rigorous checksum comparison for both Packfiles and Index files before finalizing the transaction.

The Exploit: Schrödinger's Repository

How do we weaponize this? We don't need a complex buffer overflow or ROP chain. We just need to lie.

The Attack Vector: MITM or Malicious Upstream

Imagine a scenario where a developer (or a CI pipeline) clones a repository from an HTTP server. An attacker performs a Man-in-the-Middle (MITM) attack. Usually, this is hard because Git over HTTPS validates the connection, and Git itself validates the data integrity. If the attacker modifies the stream, the checksum fails, and the clone aborts.

With CVE-2026-25934, the data integrity check is gone. The attacker can modify the packfile in transit.

  1. The Setup: The victim runs git clone http://insecure-repo.local/app.git using a tool built on go-git.
  2. The Interception: The attacker intercepts the GET request for the .pack file.
  3. The Switch: The attacker serves a packfile where the content of main.go is malicious, but the Packfile header and structure remain valid enough to parse.
  4. The Result: go-git reads the corrupted packfile. It ignores the fact that the SHA-1 checksum at the end does not match the hashed content. The malicious main.go is written to the object store.

This allows for Cache Poisoning. If go-git caches this repository, subsequent builds will use the corrupted code, even if the network connection is later secured. The repository is now in a zombie state: valid according to go-git, but corrupt according to reality.

The Impact: Trust Issues

While the CVSS score is a modest 4.3, do not let that fool you. In the world of supply chain security, integrity is everything. The impact here falls into two buckets:

  1. Silent Data Corruption: This is the nightmare scenario for DevOps. A deployment tool fails to deploy, or deploys the wrong thing, and logs nothing about an error. Debugging this requires manually running git fsck on the server, which nobody does until it is too late.
  2. Security Bypass: Many security tools use go-git to scan repositories for secrets or vulnerabilities. If an attacker can feed a corrupted packfile that hides the secrets from the scanner (by corrupting the specific object structure) but allows the scanner to finish without error, the tool reports "Clean" when the repo is actually "Dirty".

It is a "Low" severity for a web server, but a "High" anxiety inducing bug for a Release Engineer.

The Fix: Trust, But Verify

The fix is straightforward: upgrade. The maintainers released v5.16.5 which re-introduces the sanity checks that should have been there all along.

Remediation Steps

  1. Update go.mod:
    go get github.com/go-git/go-git/v5@v5.16.5
  2. Audit Existing Stores: If you maintain long-lived repositories cloned via vulnerable versions of go-git, the update won't magically fix already-corrupted data on disk. You need to verify them:
    # Run this in your git directories
    git fsck --full

> [!NOTE] > If git fsck screams at you about "bad sha1" or "corrupt pack", delete the repo and re-clone it with the patched library. Do not try to surgically repair it.

Developers relying on go-git should also consider adding application-level checksum verification if they are handling high-value artifacts, because as we learned today, you can't always trust the library to read the fine print.

Official Patches

go-gitOfficial Release Notes

Technical Appendix

CVSS Score
4.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N

Affected Systems

Go-based CI/CD systems (e.g., ArgoCD, Flux - depending on version deps)Vulnerability scanners using go-gitCustom DevOps tooling written in GoGit-based CMS or Wiki software

Affected Versions Detail

Product
Affected Versions
Fixed Version
go-git/go-git
go-git
< 5.16.55.16.5
AttributeDetail
CWE IDCWE-354
Attack VectorNetwork
CVSS Score4.3 (Medium)
ImpactData Integrity Loss
Exploit StatusTheoretical / PoC
Patch Date2026-02-09

MITRE ATT&CK Mapping

T1565.002Data Manipulation: Transmitted Data Manipulation
Impact
T1195.002Supply Chain Compromise: Compromise Software Supply Chain
Initial Access
CWE-354
Improper Validation of Integrity Check Value

The product does not validate or incorrectly validates the integrity check value of a message or file.

Known Exploits & Detection

TheoreticalMITM injection of malformed packfiles to cause integrity drift.

Vulnerability Timeline

Vulnerability Disclosed
2026-02-09
Patch v5.16.5 Released
2026-02-09
GHSA Advisory Published
2026-02-09

References & Sources

  • [1]GHSA-37cx-329c-33x3
  • [2]NVD Analysis

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.