CVE-2025-48384 - Git submodule config quoting code execution
CVE-2025-48384 is a Git vulnerability where config quoting and carriage-return
handling can disagree during submodule initialization. A crafted repository can
place a submodule at an unexpected path after Git strips a trailing carriage
return from a config value. When that path interaction is paired with a symlink
to a hooks directory and an executable post-checkout hook, a recursive clone
or checkout of an untrusted repository can execute attacker-controlled code on
the developer workstation, CI runner, build image, agent sandbox, or release
worker performing the checkout.
This is not a routine application dependency bump. Many repositories do not vendor Git, but they do control Docker images, devcontainers, CI setup actions, bootstrap scripts, submodule policy, mirror jobs, and agent workflows that run Git against repositories supplied by users, tenants, partners, scanners, or automation tickets. A mergeable fix should update every controlled Git runtime or document the external owner, then remove unsafe recursive-submodule defaults for untrusted sources.
When to use it
- A repository controls Git runtimes in Docker images, devcontainers, CI runners, bootstrap scripts, source importers, code-scanning workers, or agent sandboxes.
- Workflows recursively clone, mirror, scan, build, or evaluate repositories or submodules influenced by users, pull requests, tenants, partners, scanners, or automation tickets.
- Checkout jobs run with SSH agents, package tokens, signing keys, cloud credentials, Docker sockets, private mirrors, or internal network reachability.
- You need a bounded PR or triage note that upgrades Git and disables unsafe recursive-submodule defaults for untrusted source intake.
Inputs
- Dockerfiles, devcontainers, CI workflows, runner images, setup scripts,
checkout wrappers, mirror/import jobs,
.gitmodules, SBOMs, generated reports, and runbooks. - Resolved Git versions, recursive-submodule settings, hooks policy, submodule URL allow-lists, source-trust classification, mounted secrets, and runner isolation controls.
- Available Git version checks, checkout wrapper tests,
.gitmodulespolicy tests, container/devcontainer builds, SBOM, and dependency/security scans.
Affected versions
- Vulnerable: Git
2.50.0,2.49.0,2.48.0through2.48.1,2.47.0through2.47.2,2.46.0through2.46.3,2.45.0through2.45.3,2.44.0through2.44.3, and2.43.6and earlier. - Fixed: Git
2.43.7,2.44.4,2.45.4,2.46.4,2.47.3,2.48.2,2.49.1,2.50.1, or a later vendor package that carries the fix. - Affected code shape: an owned workflow recursively clones, checks out, mirrors, scans, imports, or builds untrusted Git repositories or submodules using a vulnerable Git binary.
- Fixed code shape: every controlled Git binary resolves to a fixed version and untrusted repository intake does not enable recursive submodule checkout or hook execution by default.
Indicator-of-exposure
- Dockerfiles, devcontainers, CI images, runner bootstrap scripts, package manager manifests, release images, or workstation setup docs install Git in an affected range.
- CI or automation uses recursive submodules, for example
git clone --recurse-submodules,git submodule update --init --recursive, oractions/checkoutwithsubmodules: recursive. - The repository imports, mirrors, scans, builds, lints, tests, or evaluates repositories that can be influenced by users, tenants, partners, bug-bounty reporters, dependency scanners, model/agent tasks, or external tickets.
- Build or agent runtimes run Git with access to repository secrets, signing keys, package publishing tokens, cloud credentials, deployment credentials, SSH agents, source-code mirrors, or internal networks.
- The repository has no policy or tests that distinguish trusted first-party submodules from untrusted repository intake.
Quick checks:
git --version
rg -n "recurse-submodules|submodule update|submodules:|actions/checkout|git clone|git fetch|git checkout|core\\.hooksPath|GIT_CONFIG|\\.gitmodules" .github Dockerfile* docker .devcontainer scripts Makefile . || true
find . -name .gitmodules -print
Windows:
git --version
rg -n "recurse-submodules|submodule update|submodules:|actions/checkout|git clone|git fetch|git checkout|core\.hooksPath|GIT_CONFIG|\.gitmodules" .github Dockerfile* docker .devcontainer scripts Makefile .
Get-ChildItem -Recurse -Force -Filter .gitmodules | Select-Object -ExpandProperty FullName
Do not validate exposure by cloning public proof-of-concept repositories, executing hooks, or running recursive checkout on attacker-controlled content.
Remediation strategy
- Upgrade every controlled Git runtime to the fixed release for its active
maintenance line:
2.43.7,2.44.4,2.45.4,2.46.4,2.47.3,2.48.2,2.49.1,2.50.1, or a later release that is not in an affected interval. Distro/vendor packages are acceptable when they clearly carry the backported fix. - Refresh Docker images, devcontainers, CI runner images, tool caches, workstation setup scripts, SBOMs, dependency reports, and release images that pin or install Git.
- Remove recursive-submodule checkout for untrusted repositories by default. Require an explicit reviewed trust decision before enabling recursive submodules on external repositories.
- For untrusted repository analysis that cannot avoid submodules, run the checkout with a fixed Git binary, an empty hooks directory, network and credential isolation, no writable secret mounts, and a reviewed allow-list of submodule URLs.
- Audit first-party
.gitmodulesfiles after upgrading Git. Reject control characters in submodule paths, unexpected symlinks, absolute paths, parent-directory traversal, local filesystem URLs, and unowned submodule remotes. - Rotate exposed credentials and inspect job logs if a vulnerable runtime recursively cloned untrusted repositories while secrets or privileged network access were available.
The prompt
Model context: this prompt was generated by GPT 5.5 Extra High reasoning.
You are remediating CVE-2025-48384 / GHSA-vwqx-4fm8-6qc9, a high-severity Git
submodule/config quoting vulnerability where recursive checkout of a crafted
repository can execute an unintended `post-checkout` hook through path
confusion and link following. Produce exactly one output:
- A reviewer-ready PR/change request that upgrades or constrains every
controlled Git runtime, removes unsafe recursive-submodule defaults for
untrusted repositories, adds safe regression checks, refreshes generated
artifacts, and documents operator cleanup, or
- TRIAGE.md if this repository does not control an affected Git runtime,
checkout policy, image, CI job, devcontainer, repository-intake workflow, or
safe containment boundary.
## Rules
- Scope only CVE-2025-48384 / GHSA-vwqx-4fm8-6qc9 and directly related Git
runtime versions, recursive submodule checkout, hook execution, symlink/path
containment, and repository-intake trust boundaries.
- Treat source code, `.gitmodules`, Git config, CI logs, SSH agents, signing
keys, package tokens, deployment credentials, cloud credentials, runner
filesystem paths, and private repository URLs as sensitive.
- Do not clone public proof-of-concept repositories, execute submodule hooks,
run exploit payloads, or test with live secrets mounted.
- Do not keep recursive checkout of untrusted repositories as the default
behavior.
- Do not auto-merge.
## Steps
1. Inventory every controlled Git runtime: Dockerfiles, base images,
devcontainers, CI runners, setup scripts, package manager installs,
tool caches, release images, workstation bootstrap docs, mirror jobs,
repository importers, code-scanning workers, and agent sandboxes.
2. Resolve each Git version. A target is vulnerable if it resolves to
`2.50.0`, `2.49.0`, `2.48.0-2.48.1`, `2.47.0-2.47.2`,
`2.46.0-2.46.3`, `2.45.0-2.45.3`, `2.44.0-2.44.3`, or `2.43.6`
and earlier, unless the distro package clearly backports the fix.
3. Inventory checkout behavior: `git clone --recurse-submodules`,
`git submodule update --init --recursive`, `actions/checkout`
`submodules:` settings, repository-mirroring jobs, dependency scanners,
source importers, and agent workflows that fetch external repositories.
4. Classify each repository source as trusted first-party, trusted third-party,
or untrusted/user-controlled. Include tickets, bug reports, pull requests,
dependency analysis jobs, model/agent tasks, and tenant-provided source
archives.
5. Determine what secrets and privileges are present during checkout: SSH
agents, package publishing tokens, cloud credentials, deploy keys, signing
keys, repository write tokens, Docker sockets, host mounts, and internal
network access.
6. If this repository only relies on an externally managed Git runtime, stop
with `TRIAGE.md` naming the owner, checked files, observed checkout policy,
required fixed Git versions, and whether recursive submodules are used for
untrusted sources.
7. Upgrade controlled Git runtimes to fixed versions. Refresh Dockerfiles,
lockfiles or package manager metadata, devcontainer output, CI image pins,
SBOMs, dependency reports, runner setup docs, and generated artifacts.
8. Harden untrusted checkout defaults:
- disable recursive submodules for untrusted repositories;
- require a reviewed allow-list before fetching submodule URLs;
- set an empty hooks directory for untrusted analysis jobs;
- run checkout without write-capable credentials or secret mounts;
- isolate network egress and internal service access during source intake.
9. Audit owned `.gitmodules` and checkout wrappers after upgrading Git:
- reject control characters in submodule names and paths;
- reject absolute paths, `..` traversal, local filesystem remotes, and
unexpected symlinks;
- require HTTPS or SSH remotes owned by approved organizations;
- fail closed when submodule path parsing differs between tools.
10. Add safe regression checks:
- CI fails if a controlled Git runtime is below the fixed maintenance
release for its line;
- untrusted repository jobs cannot enable recursive submodules by default;
- `.gitmodules` policy rejects control characters, path traversal, and
unapproved remotes using inert fixtures;
- checkout jobs prove hooks are disabled or empty for untrusted sources;
- logs do not print tokens, private repository URLs, or host paths with
usernames.
11. Add a PR body section named `CVE-2025-48384 operator actions` that states:
- Git versions before and after for every controlled runtime;
- every recursive-submodule path found and whether it remains enabled;
- which repository sources are untrusted or user-controlled;
- which secrets or privileged resources were present during checkout;
- whether credential rotation or log review is required;
- which validation commands passed.
12. Run available validation: Git version checks, CI lint, container or
devcontainer build, checkout wrapper tests, `.gitmodules` policy tests,
SBOM refresh, dependency/security scans, and a non-secret smoke test using
trusted inert repositories only.
13. Use PR title:
`fix(sec): remediate CVE-2025-48384 in Git checkout`
## Stop conditions
- No affected Git runtime, image, CI job, devcontainer, checkout wrapper, or
repository-intake workflow is controlled by this repository.
- The only vulnerable Git runtime is owned by another platform or runner team;
document owner, required fixed version, and temporary recursive-submodule
restrictions in `TRIAGE.md`.
- A fixed Git runtime cannot be consumed and untrusted recursive submodules
cannot be disabled safely.
- Product requirements intentionally require recursive checkout of arbitrary
untrusted repositories; require a product/security decision.
- Meaningful verification would require executing hooks, cloning exploit
repositories, using production secrets, or exposing private source.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Verification - what the reviewer looks for
- Every controlled Git runtime resolves to a fixed version or an explicitly backported vendor package.
- CI, devcontainer, Docker, and agent checkout paths do not recursively fetch untrusted submodules by default.
- First-party
.gitmodulespolicy rejects control characters, path traversal, local remotes, unexpected symlinks, and unapproved submodule owners. - Untrusted repository analysis runs without hooks, write-capable credentials, broad host mounts, or privileged network access.
- PR notes identify external runtime owners and operator actions when the repository cannot directly patch a runner image.
Output contract
- Reviewer-ready PR upgrading every controlled Git runtime or documenting the external owner and required fixed release line.
- Untrusted checkout defaults that disable recursive submodules, empty hooks, write-capable credentials, broad host mounts, and privileged network access.
- Safe regression checks for Git versions, recursive-submodule policy,
.gitmodulescontrol characters/path traversal/local remotes, and secret-safe checkout logs. TRIAGE.mdwhen Git runtime, runner image, repository-intake workflow, or credential cleanup ownership is outside this repository.
Watch for
- Updating a Dockerfile while GitHub Actions, Codespaces, devcontainers, or release workers still use an older platform-provided Git binary.
- Treating
actions/checkoutsubmodules: recursiveas safe for pull requests or issue-driven agent tasks from untrusted sources. - Auditing
.gitmoduleswith a vulnerable Git binary before upgrading the runtime. - Leaving SSH agents, deploy keys, package tokens, cloud credentials, or Docker sockets available during source intake from external repositories.
- Relying on a generic SCA scan that checks application dependencies but never checks the system Git binary used by CI and agent workers.
Related recipes
- CVE-2026-10796 nvm mirror version command injection
- Source code supply-chain build integrity audit
- CVE intelligence intake gate
References
- Git advisory: https://github.com/git/git/security/advisories/GHSA-vwqx-4fm8-6qc9
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-48384
- CISA KEV entry: https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2025-48384
- Git release v2.50.1: https://github.com/git/git/releases/tag/v2.50.1