## Ticket: CVE-2026-44471 — gitoxide (`gix-fs`) symlink worktree escape on checkout

**Advisory**: GHSA-f89h-2fjh-2r9q — https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-f89h-2fjh-2r9q
**CVE**: CVE-2026-44471 | **CWE-59** (Link Following)
**Severity**: High — CVSS 7.8
**Package**: `gix-fs` crate (part of gitoxide, crates.io) | **Repository**: https://github.com/GitoxideLabs/gitoxide

### Impact

During worktree checkout, the `gix-fs` crate processes **symlink index
entries** in a way that lets a malicious git tree **reuse a path prefix** to
write an attacker-controlled symlink into an existing directory the user can
write to.

A later index entry is then resolved *through* that planted symlink, so files
are written outside the intended worktree directory. An attacker who controls
the contents of a git tree the victim checks out can therefore place files
anywhere the victim user can write.

### Affected / fixed versions

Affected: `gix-fs` `< 0.21.1` (gitoxide `< 0.21.1`).
Fixed: **`gix-fs 0.21.1`**.

Reproduce on a vulnerable build (**`gix-fs 0.21.0`**) and verify the fix on
**`gix-fs 0.21.1`**.

### Where to look

The repository is https://github.com/GitoxideLabs/gitoxide . Inspect the diff
between the `gix-fs` releases to confirm the root cause and the guard:

```bash
git clone https://github.com/GitoxideLabs/gitoxide.git
cd gitoxide && git log --oneline -- gix-fs
# compare the gix-fs 0.21.0 and 0.21.1 release points
```

The fix prevents a malicious symlink entry from being honored during checkout
so a later entry can no longer resolve through a planted symlink and escape the
worktree.

### Reproduction approach

No network service, database, or browser is required — the difference is
observable as a file written outside the worktree on the local filesystem.

1. Build a small Rust binary depending on the `gix` crate, pinned so that its
   `gix-fs` dependency resolves to the **vulnerable** `0.21.0`.
2. Construct a crafted malicious git tree fixture: a symlink entry pointing
   outside the worktree plus a later entry that reuses the path prefix so the
   checkout resolves through the planted symlink.
3. Check the tree out into a worktree via the `gix` checkout path and inspect
   the filesystem for files written outside the worktree directory.
4. Repeat with the **fixed** build: `gix-fs 0.21.1`.

### Expected result

| Build | Checkout of the crafted malicious git tree | Observable |
|-------|---------------------------------------------|------------|
| `gix-fs 0.21.0` (vulnerable) | malicious symlink entry honored, later entry follows it | **file/symlink written outside the worktree directory** |
| `gix-fs 0.21.1` (fixed) | malicious symlink entry refused | nothing written outside the worktree; entry errors/skipped |

- **Vulnerable indicator**: after checkout, a symlink and/or file appears on the
  filesystem at a path outside the intended worktree directory.
- **Fixed indicator**: the checkout refuses the malicious entry; no file or
  symlink is created outside the worktree directory.

### Expected artifacts

- `reproduction_steps.sh` — builds the Rust binary against each `gix-fs`
  version, constructs the malicious git tree fixture, and runs the checkout.
- `validation_verdict.json` — `verdict: confirmed`, with the vulnerable and
  fixed indicators captured.
- Logs capturing the checkout output and the filesystem state for `0.21.0` and
  `0.21.1`.
