Skip to content

CVE-2026-44471: Verified Repro With Script Download

CVE-2026-44471: gitoxide gix-fs : symlink worktree escape on checkout writes files outside the worktree

CVE-2026-44471 is verified against gix-fs · cargo. Affected versions: gix-fs <= 0.21.0 (gitoxide < 0.21.1). Fixed in gix-fs 0.21.1. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00155.

REPRO-2026-00155 gix-fs · cargo May 22, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.8
Reproduced in
33m 22s
Tool calls
334
Spend
$4.18
01 · Overview

What Is CVE-2026-44471?

CVE-2026-44471 (CWE-59, Link Following) is a high-severity symlink worktree escape in the gix-fs crate (part of the gitoxide project), where checking out a malicious git tree can write attacker-controlled files outside the intended worktree directory. Pruva reproduced it (reproduction REPRO-2026-00155).

02 · Severity & CVSS

CVE-2026-44471 Severity & CVSS Score

CVE-2026-44471 is rated high severity, with a CVSS base score of 7.8 out of 10.

HIGH threat level
7.8 / 10 CVSS base
Weakness CWE-59 (Link Following)

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected gix-fs Versions

gix-fs · cargo versions gix-fs <= 0.21.0 (gitoxide < 0.21.1) are affected.

How to Reproduce CVE-2026-44471

$ pruva-verify REPRO-2026-00155
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00155/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-44471

Reproduced by Pruva's autonomous agents — 334 tool calls over 33 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 1,209 events · 334 tool calls · 33 min
33 minDuration
334Tool calls
289Reasoning steps
1,209Events
Agent activity over 33 min
Support
64
Repro
836
Variant
305
0:0033:22

Root Cause and Exploit Chain for CVE-2026-44471

Summary

CVE-2026-44471 is a symlink worktree escape vulnerability in the gix-fs crate (part of the gitoxide project). During worktree checkout, when the gix-fs::Stack reuses a previously cached leaf path component (e.g., a symlink) as a directory parent for a subsequent path, it skips re-invoking the delegate's push() callback. This bypasses collision detection and allows a malicious symlink planted earlier in the checkout to redirect later file writes outside the intended worktree directory.

Impact

  • Package/component affected: gix-fs crate (used transitively by gix-worktree and gix during checkout)
  • Affected versions: gix-fs < 0.21.1
  • Fixed versions: gix-fs 0.21.1
  • Risk level: High (CVSS 7.8)
  • Consequences: An attacker who controls a git repository can cause files to be written to arbitrary locations writable by the victim user during checkout, via a malicious tree containing a symlink entry followed by a file entry that reuses the symlink's path prefix.

Root Cause

The bug is in gix_fs::Stack::make_relative_path_current() (in gix-fs/src/stack.rs). When a previously cached leaf component needs to be promoted to a directory parent (because a later path has additional child components), the old code called delegate.push_directory() directly without first calling delegate.push(false, self).

The push() callback is where gix-worktree's delegate performs collision detection: it checks whether the path already exists as a symlink or file and either errors out or unlinks it. By skipping this callback during leaf-to-directory transitions, a symlink could persist and later paths would resolve through it.

The fix (commit 93d0ff6 in the gitoxide repository) adds delegate.push(false, self)?; before delegate.push_directory(self)?; when promoting a cached leaf, and also adds proper state restoration if either callback fails.

Reproduction Steps

The reproduction script is repro/reproduction_steps.sh. It performs the following steps:

  1. Creates a minimal Rust binary that depends on gix-worktree = "=0.52.0" and pins gix-fs to either =0.21.0 (vulnerable) or =0.21.1 (fixed). A local patched copy of gix-hash = "=0.25.0" is used via [patch.crates-io] to resolve a compilation incompatibility with modern Rust.
  2. The binary creates a worktree directory and a "forbidden" directory outside it.
  3. It instantiates a gix_worktree::Stack configured for checkout (stack::State::for_checkout).
  4. It calls cache.at_path("link", IS_SYMLINK) to get the path where a symlink would be created, then manually creates a symlink at that path pointing to the forbidden directory.
  5. It calls cache.at_path("link/file", IS_FILE) — this exercises the vulnerable leaf-to-directory promotion.
  6. If the call succeeds (vulnerable), the script writes a file to the returned path and verifies it appears inside the forbidden directory, proving the escape.
  7. If the call errors with AlreadyExists (fixed), the script confirms no file was written outside the worktree.
Expected evidence of reproduction
  • Vulnerable (gix-fs 0.21.0): the binary prints VULNERABLE: file escaped worktree to .../forbidden/file and exits 0. The forbidden directory contains the escaped file.
  • Fixed (gix-fs 0.21.1): the binary prints FIXED: symlink collision blocked, no escape and exits 1 (indicating the bug is no longer present). The forbidden directory remains empty.

Evidence

  • logs/vulnerable.log — captures the vulnerable run showing the file was written to the forbidden directory:
    VULNERABLE: file escaped worktree to .../forbidden/file
    Exit code: 0
    Forbidden:
    -rw-r--r-- 1 root root 7 ... file
    
  • logs/fixed.log — captures the fixed run showing the collision was blocked:
    FIXED: symlink collision blocked, no escape
    Exit code: 1
    Forbidden:
    (empty)
    
  • logs/summary.log — confirms the differential outcome:
    Vulnerable exit code: 0
    Fixed exit code: 1
    CONFIRMED: Symlink worktree escape reproduced on vulnerable version and blocked on fixed version
    
  • logs/runtime_manifest.json — structured record of the two runs.
  • Environment: Rust 1.94.1 on Linux x86_64.

Recommendations / Next Steps

  1. Upgrade: All consumers of gix-fs should upgrade to >= 0.21.1.
  2. Audit callers: Any custom delegates using gix_fs::Stack should ensure their push() implementation performs security validation on all components, not just leaf components.
  3. Regression testing: The fix commit includes regression tests in gix-worktree/tests/worktree/stack/create_directory.rs that should be maintained and run in CI.

Additional Notes

  • The reproduction was confirmed idempotent: running repro/reproduction_steps.sh twice produced identical results.
  • The reproduction requires a patched gix-hash 0.25.0 to compile on Rust 1.94+ due to upstream match self exhaustiveness lint issues; this is a build-time incompatibility unrelated to the vulnerability under test.

CVE-2026-44471 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:19
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-44471 · cve-2026
0:03
0:04
0:08
0:09
web search
0:11
0:16
web search
0:18
0:19
web search
0:21
0:22
0:35
0:36
web search
0:37
0:38
0:51
0:52
web search
1:03
1:04
web search
1:19

Artifacts and Evidence for CVE-2026-44471

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-44471

Upgrade gix-fs · cargo to gix-fs 0.21.1 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-44471 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-44471

How does the CVE-2026-44471 symlink escape attack work?

A malicious git tree contains a symlink entry followed by a file entry that reuses the symlink's path prefix as a directory parent. Because gix-fs reuses the cached leaf (the symlink) without re-running collision detection, the later file-write index entry resolves through the planted symlink, letting an attacker who controls a repository's tree write files anywhere the checking-out user can write, outside the worktree.

Which gix-fs versions are affected by CVE-2026-44471, and where is it fixed?

gix-fs <= 0.21.0 (gitoxide < 0.21.1) is affected. It is fixed in gix-fs 0.21.1 — upgrade to 0.21.1 or later.

How severe is CVE-2026-44471?

The record rates it high severity.

How can I reproduce CVE-2026-44471?

Download the verified script from this page and run it in an isolated environment against gix-fs <= 0.21.0. It checks out a crafted git tree containing a symlink entry followed by a file entry that reuses the symlink's path prefix, and shows the resulting file being written outside the worktree; the fixed 0.21.1 build blocks the escape.
11 · References

References for CVE-2026-44471

Authoritative sources for CVE-2026-44471 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.