CVE-2025-48384 Overview
CVE-2025-48384 is a high-severity vulnerability in Git, the distributed revision control system maintained by the git-scm project. The flaw stems from inconsistent handling of carriage return (CR) characters when reading and writing Git configuration values. When a submodule path contains a trailing CR, Git checks out the submodule to an attacker-controlled location. If the altered location is reached through a symlink pointing to the submodule hooks directory, an executable post-checkout hook in the submodule can run automatically after checkout. The vulnerability is tracked under CWE-59: Improper Link Resolution Before File Access and is listed in the CISA Known Exploited Vulnerabilities catalog.
Critical Impact
Cloning a malicious repository with --recursive can trigger arbitrary code execution on the developer's machine through an unintentionally executed submodule hook.
Affected Products
- Git (git-scm) versions prior to 2.43.7, 2.44.4, 2.45.4, 2.46.4, 2.47.3, 2.48.2, 2.49.1, and 2.50.1
- Debian Linux 11.0 (Git package distributed via Debian LTS)
- Apple Xcode (bundled Git toolchain)
Discovery Timeline
- 2025-07-08 - CVE-2025-48384 published to the National Vulnerability Database
- 2025-07-08 - GitHub Security Advisory GHSA-vwqx-4fm8-6qc9 released by the Git project
- 2025-10 - Debian LTS Announcement issued for Debian 11
- 2025-11-06 - Last updated in NVD database
Technical Details for CVE-2025-48384
Vulnerability Analysis
The vulnerability arises from asymmetric handling of trailing CRLF characters in Git's configuration parser. When Git reads a config value, it strips any trailing carriage return and line feed. However, when Git writes a config entry, values with a trailing carriage return are not quoted. The result is that a CR written into a .gitmodules file is silently dropped during the next read, yielding a different value than the one originally written.
Attackers exploit this asymmetry against submodule path entries. A crafted submodule entry contains a path with a trailing CR. Git uses the unmodified path during one operation and the CR-stripped path during another. By combining the inconsistency with a symlink that points the altered path into the submodule's hooks directory, the attacker places a post-checkout script at a location Git later treats as the hooks directory. Git executes the hook automatically when checkout completes.
Root Cause
The root cause is the mismatch between config writer and reader semantics for trailing whitespace. The writer treats a trailing CR as a benign data byte, while the reader treats it as line terminator noise. This violates round-trip integrity for config values [CWE-59].
Attack Vector
Exploitation requires a victim to clone a malicious repository recursively, for example with git clone --recursive or git submodule update --init. The attacker controls the .gitmodules file and includes both a CR-terminated submodule path and a symlink that redirects the parsed path into the submodule's .git/hooks directory. After checkout, Git executes the planted post-checkout hook with the privileges of the user running the clone.
No synthetic exploit code is reproduced here. Refer to the GitHub Security Advisory GHSA-vwqx-4fm8-6qc9 and the Full Disclosure mailing list post for the upstream technical write-up.
Detection Methods for CVE-2025-48384
Indicators of Compromise
- .gitmodules files containing submodule path values with embedded carriage return (\r) bytes
- Symbolic links inside a cloned repository that resolve into a submodule's .git/hooks/ directory
- Unexpected executable files named post-checkout, post-merge, or similar inside submodule hook directories shortly after a clone
- Child processes spawned by git or git-submodule immediately after a clone --recursive or submodule update operation
Detection Strategies
- Scan repository content and CI build logs for .gitmodules entries whose path fields contain non-printable trailing bytes
- Alert on shell, scripting, or compiler processes whose parent process is git, git-submodule, or git-checkout on developer endpoints and build agents
- Inventory installed Git versions across endpoints and build infrastructure and flag any version older than the fixed releases
Monitoring Recommendations
- Forward developer workstation and CI runner process telemetry to a centralized analytics platform for parent-child process analysis of git invocations
- Monitor outbound network connections initiated by short-lived shells spawned under git to identify post-exploitation command and control
- Track filesystem events that create symbolic links inside .git/ directories during clone operations
How to Mitigate CVE-2025-48384
Immediate Actions Required
- Upgrade Git to one of the fixed versions: 2.43.7, 2.44.4, 2.45.4, 2.46.4, 2.47.3, 2.48.2, 2.49.1, or 2.50.1
- Apply the Debian LTS update for Debian 11 as described in the Debian LTS Announcement
- Update Apple Xcode to a release that bundles a patched Git toolchain
- Audit recent recursive clones of untrusted repositories on developer endpoints and CI runners for signs of hook execution
Patch Information
The Git project published GHSA-vwqx-4fm8-6qc9 along with patched releases across all supported branches. Downstream distributions including Debian and Apple have shipped corresponding updates. Operators should prioritize patching given the vulnerability's inclusion in the CISA Known Exploited Vulnerabilities catalog and an EPSS score of 0.603% (69.7th percentile).
Workarounds
- Avoid cloning untrusted repositories with --recursive; instead clone without submodules and review .gitmodules before running git submodule update
- Set protocol.file.allow=user and disable automatic submodule initialization in CI pipelines until patched Git binaries are deployed
- Run Git operations against untrusted sources inside ephemeral, network-restricted sandboxes or containers
# Verify the installed Git version meets the fixed release
git --version
# Disable recursive submodule fetch during clone of untrusted sources
git clone <repo-url>
grep -P '\r' .gitmodules && echo 'Suspicious CR detected in .gitmodules'
# Only initialize submodules after manual review
git submodule update --init --recursive
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


