Aug 8, 2026·7 min read·1 visit
A path traversal flaw in go-git's reference processing allows a malicious remote server to overwrite local repository configuration files (such as .git/config) during clone or fetch operations, potentially leading to arbitrary command execution.
CVE-2026-71557 is a path traversal vulnerability in go-git, a pure-Go implementation of Git. In vulnerable versions, the filesystem-backed storage engine fails to validate reference names before mapping them to on-disk paths. An attacker hosting a malicious Git server can advertise references containing directory traversal sequences, such as 'refs/heads/../../config', to write or overwrite files outside the intended reference storage directory.
The go-git library is a pure-Go implementation of the Git version control system, widely used in automated continuous integration and continuous deployment (CI/CD) pipelines, developer tools, and cloud-native applications. To persist Git metadata, the library implements a storage abstraction layer. The filesystem-backed storage engine, located within the storage/filesystem package, manages Git object databases, configuration details, and logical references such as branches and tags.
In Git architectures, loose references function as pointers to specific commit hashes and are traditionally stored as physical files on disk under the .git/refs/ directory. Prior to the patch, the storage/filesystem/dotgit component processed remote reference names directly without verifying if the path resolution logic remained within the designated directory boundary. This administrative failure exposes a path traversal vulnerability classified under CWE-22, enabling unauthenticated remote actors to bypass intended directory constraints.
The attack surface is exposed during clone and fetch operations where a client connects to a remote repository. When a remote server advertises its references, the vulnerable client writes these references to the local filesystem using the exact names received from the server. By crafting malicious reference names that incorporate relative directory traversal sequences, an attacker can manipulate the file paths resolved by the client, causing files to be created or overwritten outside the designated reference storage area.
The root cause of CVE-2026-71557 resides in the reference persistence logic of storage/filesystem/dotgit/dotgit.go. When saving a reference, the library converts the logical reference name into a string and passes it directly to internal filesystem storage routines. Specifically, the SetRef function invokes setRef(fileName, content, old) using the raw string representation of the reference name returned by r.Name().String().
The filesystem wrapper implements directory organization by joining the base path of the .git directory with the provided reference name using helper functions such as d.fs.Join(".", name). In Go, the Join function evaluates the path, but the underlying filesystem interfaces often execute lexical path cleaning or delegate normalization to the operating system's system calls. Consequently, input strings containing relative path segments like ../ are evaluated dynamically.
When an attacker-controlled remote server advertises a reference name such as refs/heads/../../config, the library attempts to write this reference. The path resolution resolves the string relative to the repository root, effectively neutralizing the refs/heads/ prefix and targeting .git/config directly. Because the code lacked validation checks to verify whether the final resolved path remained within the bounds of the reference storage directory, the application allows arbitrary out-of-bounds writes.
The vulnerability was addressed by introducing validation functions to enforce boundaries on reference names. The following code comparison demonstrates the vulnerability remediation introduced in storage/filesystem/dotgit/dotgit.go.
Before the patch, reference names were accepted and joined without verification:
// Vulnerable pattern in dotgit.go
func (d *DotGit) SetRef(r *plumbing.Reference, old *plumbing.Reference) error {
fileName := r.Name().String()
// The filename was passed directly, enabling directory traversal
return d.setRef(fileName, []byte(r.Hash().String()+"\n"), old)
}The patch introduces a strict boundary validation step before any filesystem operation occurs on the reference name:
// Patched pattern in dotgit.go
func (d *DotGit) SetRef(r *plumbing.Reference, old *plumbing.Reference) error {
// First, validate the reference name logically and structurally
if err := validReferenceName(r.Name()); err != nil {
return err
}
fileName := r.Name().String()
return d.setRef(fileName, []byte(r.Hash().String()+"\n"), old)
}The remediation implements the validReferenceName validation function. This helper performs critical validation routines to sanitize reference names, ensuring they represent safe paths under the .git directory:
func validReferenceName(name plumbing.ReferenceName) error {
// 1. Verifies the name is structurally safe and within the refs/ namespace
if !name.IsSafe() {
return fmt.Errorf("%w: %q is not under refs/ nor a valid pseudo-ref", ErrReferenceNameEscape, string(name))
}
s := string(name)
for i := 0; i < len(s); i++ {
if s[i] < 0x20 || s[i] == 0x7f {
return fmt.Errorf("%w: %q", ErrReferenceNameEscape, s)
}
}
// 2. Splits the name by OS-agnostic separators to catch relative directory jumps
for _, part := range strings.FieldsFunc(s, isPathSep) {
// 3. Rejects HFS+ and NTFS directory bypass tricks
if part == "." || pathutil.IsHFSDot(part, ".") || pathutil.IsNTFSDot(part, ".", "") {
return fmt.Errorf("%w: %q", ErrReferenceNameEscape, s)
}
}
return nil
}The patch is comprehensive because it handles operating-system-specific directory traversal techniques. It uses isPathSep to recognize both forward slashes and backslashes as path separators, preventing exploitation on Windows machines that treat backslashes as directory delimiters. Furthermore, it incorporates IsHFSDot and IsNTFSDot checks from the pathutil module to block Unicode normalization bypasses on HFS+ (macOS) and NTFS (Windows) environments, providing robust, platform-agnostic protection.
An attack leveraging CVE-2026-71557 requires the victim to perform a Git operation, such as a clone or a fetch, against a repository hosted on a server controlled by the attacker. No authentication is typically needed beyond the standard access permissions required to initiate the cloning process. The vulnerability triggers automatically as part of the initial reference handshake.
During the reference discovery phase, the malicious Git server sends a list of references and their corresponding commit hashes. The server includes a crafted reference name that contains relative path sequences targeting sensitive local configuration files, as shown below:
refs/heads/../../config
When the client processes this reference, it invokes SetRef to write the commit hash onto disk. The path joining logic resolves the target destination to .git/config instead of a subdirectory inside .git/refs/. The contents written to .git/config can alter repository configuration parameters, such as defining malicious core hooks or changing origin URLs, enabling downstream execution of arbitrary code when standard Git commands are subsequently executed.
The impact of CVE-2026-71557 is classified as Medium, with a CVSS v3.1 base score of 6.3. The vulnerability does not directly expose confidential data, resulting in a Confidentiality score of None. However, it provides a High Integrity impact and Low Availability impact because an attacker can corrupt, truncate, or overwrite critical configuration metadata within the local .git repository directory.
The primary risk associated with this flaw is remote code execution (RCE). By overwriting .git/config, an attacker can register custom execution hooks or shell commands within configuration options like core.pager or fsmonitor. When the victim or an automated script runs subsequent local Git operations on the repository, the modified configuration executes the payload with the privileges of the active user.
This threat is especially acute for automated build pipelines, code analysis tools, and CI/CD systems that pull external, untrusted repositories. If these systems utilize vulnerable versions of go-git to fetch and analyze commits, a compromised or malicious repository can easily execute commands on the build agents. This can result in credential theft, lateral network movement, or supply-chain compromise.
The primary remediation path is upgrading the go-git library to a non-vulnerable version. Organizations using the v5 branch must upgrade to version v5.19.2 or later. Projects employing the experimental v6 branch must upgrade to version v6.0.0-alpha.5 or later. To perform the upgrade in a Go environment, run the following commands:
go get github.com/go-git/go-git/v5@v5.19.2
go mod tidyFor environments where immediate upgrades are not possible, several mitigation strategies can reduce the risk. Applications can be reconfigured to use in-memory storage rather than filesystem-backed storage. Since the in-memory storage engine (storage/memory) does not write references to physical paths on disk, it is immune to the directory traversal vector described in this vulnerability.
Additionally, organizations should implement strict network egress controls to prevent automated cloning processes from connecting to unapproved or public third-party Git hosts. Applying system-level sandboxing, such as executing clone operations inside isolated containers with limited privileges, restricts the impact of any potential arbitrary command execution occurring as a result of repository configuration hijacking.
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 6.3 (Medium) |
| Exploit Status | Proof-of-Concept (PoC) |
| Impact | High Integrity (I:H), Low Availability (A:L), Remote Code Execution (RCE) |
| KEV Status | Not Listed |
A symbolic link directory traversal vulnerability was identified in go-git, a pure Go implementation of the Git specification. This vulnerability allows an attacker to construct a repository that, when checked out or processed, bypasses directory boundaries to write or overwrite arbitrary files on the host filesystem.
An information disclosure vulnerability in the Nuxt development server allows adjacent network attackers to retrieve the absolute project root directory and a persistent workspace UUID by querying the unprotected Chrome DevTools workspace endpoint. This occurs when the development server is bound to a network-reachable interface, allowing requests that bypass the header-based security verification checks.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in SvelteKit's content negotiation header parser prior to version 2.70.2. An unauthenticated remote attacker can exploit this vulnerability by sending a crafted Accept header with highly repetitive malformed values. This triggers catastrophic backtracking on the single-threaded Node.js/Bun event loop, leading to CPU exhaustion and full denial of service.
An OS command injection vulnerability exists in the npm package loading component of the jsii-diff CLI tool within the AWS jsii framework. Prior to version 1.131.0, when parsing package specifiers prefixed with `npm:`, the tool concatenated user-controlled inputs directly into a shell execution string via child_process.exec. This allows attackers to execute arbitrary shell commands under the context of the running Node.js process.
CodeIgniter4 versions prior to v4.7.4 contain a protocol-spoofing vulnerability due to improper verification of upstream reverse proxy forwarding headers. Remote, unauthenticated attackers can inject headers like X-Forwarded-Proto to deceive the framework into identifying an insecure HTTP request as a secure HTTPS connection.
An SQL injection vulnerability exists in the Query Builder component of the CodeIgniter4 full-stack PHP framework. The vulnerability is located within the compilation logic of the batch delete operation, deleteBatch(). When an application chains where() conditions prior to calling deleteBatch(), the Query Builder fails to enforce or respect the escaping flags of the parameters bound to the WHERE clauses. Instead of passing these parameters through the database driver standard escaping logic, the compilation engine interpolates the raw, unescaped bound values directly into the compiled SQL string, allowing remote attackers to execute arbitrary SQL commands.