flawopen.com/Teardowns/cve-2024-32002-git-submodule-rce
CVE-2024-32002: Git Submodule Symlink RCE
CVE-2024-32002 let a crafted Git repository write through a case-colliding symlink into .git during recursive clone, allowing a hook to run before inspection. Git’s upstream fix checks the submodule destination before and after cloning and aborts on unexpected contents; upgrade to a fixed Git release.
Imagine a warehouse where signs treat A and a as the same doorway. If a submodule’s route passes through a sign that redirects into the records room (.git), files meant for one storage bay can land in Git’s control records. Git’s fix checks the destination before and after cloning and stops when its contents are unexpected.
Core Concepts & Subsystem Terms
Git Submodule- A separate Git repository embedded as a subdirectory inside a parent repository.
Symlink- A symbolic link filesystem object that redirects path traversal to another target.
Case Collision- Filesystem behavior on NTFS and APFS where paths differing only by letter case resolve to the same inode.
Git Hooks- Executable scripts in
.git/hooks/triggered automatically by git actions likepost-checkout.
Framework mappings
Root Cause Analysis
On a case-insensitive filesystem with symlink support, a crafted repository could give a submodule path that collided by case with a symlink. During recursive clone, Git could replace a directory created for the clone with that symlink and write files outside the submodule worktree into .git. A hook written there could run before the user had a chance to inspect the checkout. The upstream patch refuses to clone into a pre-existing non-empty submodule destination and, after cloning, rejects a destination whose contents are not limited to .git metadata.
Step-by-Step Attack Flow
Recursive clone reaches attacker-controlled metadata
A user recursively clones an untrusted repository on a case-insensitive filesystem where Git supports symlinks. The repository supplies submodule paths and tracked entries that collide after case folding.
The path collision crosses a trust boundary
Git can resolve the colliding submodule path through a symlink rather than into the intended submodule worktree. The affected boundary is Git’s filesystem path handling during recursive submodule clone.
Files land in Git metadata
The redirected write can place a hook in the repository’s .git area. The Git project advisory confirms that a hook can be written there and run while clone is still in progress.
The clone can execute code before review
Git runs the hook as part of the clone operation, before the user can inspect the checked-out files. Fixed Git releases add destination-state checks and abort when unexpected files are present.
Source Code: Flaw vs. Secure Implementation
This is an excerpt of Git’s upstream C change in clone_submodule(), not a standalone function. Before the fix, the shown clone path had no corresponding destination-content guard. The fix rejects a pre-existing non-empty checkout directory and checks after cloning that only .git metadata is present; its helper performs the directory-entry check. The actual implementation is linked in the upstream commit.
if (!file_exists(sm_gitdir)) {
if (safe_create_leading_directories_const(sm_gitdir) < 0)
die(_("could not create directory '%s'"), sm_gitdir);
if (run_command(&cp))
die(_("clone of '%s' into submodule path '%s' failed"),
clone_data->url, clone_data_path);
}
struct stat st;
if (!file_exists(sm_gitdir)) {
if (clone_data->require_init && !stat(clone_data_path, &st) &&
!is_empty_dir(clone_data_path))
die(_("directory not empty: '%s'"), clone_data_path);
if (safe_create_leading_directories_const(sm_gitdir) < 0)
die(_("could not create directory '%s'"), sm_gitdir);
if (run_command(&cp))
die(_("clone of '%s' into submodule path '%s' failed"),
clone_data->url, clone_data_path);
if (clone_data->require_init && !stat(clone_data_path, &st) &&
!dir_contains_only_dotgit(clone_data_path)) {
char *dot_git = xstrfmt("%s/.git", clone_data_path);
unlink(dot_git);
free(dot_git);
die(_("directory not empty: '%s'"), clone_data_path);
}
}
Engineering & System Hardening Checklist
- ✓Upgrade Git to 2.45.1, 2.44.1, 2.43.4, or later containing submodule collision guards.
- ✓Disable automatic recursive submodule cloning in untrusted repositories (git clone --no-recurse-submodules).
- ✓Enforce filesystem path collision checks in continuous integration runners and build bots.
- ✓Configure core.protectNTFS and core.protectHFS to true on multi-platform development environments.
- ✓Audit repository checkouts for suspicious symlinks targeting internal .git directories.