---
id: CVE-2026-82252
aliases:
  - GHSA-pg4w-g64p-qwhj
title: >-
  gix and gitoxide's symlinked .gitmodules are followed and parsed from outside
  of the repository
summary: >-
  gix and gitoxide's symlinked .gitmodules are followed and parsed from outside
  of the repository
severity: high
vendor: gitoxide
product: gitoxide
ecosystem: rust
affected:
  - gitoxide < 0.52.1
  - gix < 0.83.0
patched:
  - gitoxide 0.52.1
  - gix 0.83.0
published: '2026-05-05'
updated: '2026-08-29'
source: OSV
sourceUrl: 'https://osv.dev/vulnerability/GHSA-pg4w-g64p-qwhj'
references:
  - url: >-
      https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-pg4w-g64p-qwhj
  - url: 'https://github.com/GitoxideLabs/gitoxide'
tags:
  - osv
  - rust
epss: 0.00387
epssPercentile: 0.32722
ingestedAt: '2026-08-29T19:29:15.836Z'
---

## Overview

## Summary
attachments:
[pocs.zip](https://github.com/user-attachments/files/26431422/pocs.zip)


When `Repository::submodules()` loads submodule metadata, it prefers the worktree `.gitmodules` file if that path exists. In the current implementation, the path is read with `std::fs::read()`, which follows symlinks. As a result, a repository can present a symlinked `.gitmodules` that points outside the repository, and gitoxide will parse the out-of-repository bytes as submodule configuration.

This is a repository-boundary violation. A caller using the high-level submodule API can believe it is reading repository-local submodule metadata, while the bytes are actually coming from an arbitrary file outside the repository tree.

## Root cause analysis

The relevant flow is:

1. [`gix/src/repository/location.rs`](https://github.com/GitoxideLabs/gitoxide/blob/v0.52.0/gix/src/repository/location.rs) derives the worktree `.gitmodules` path as `workdir/.gitmodules`.
2. [`gix/src/repository/submodule.rs`](https://github.com/GitoxideLabs/gitoxide/blob/v0.52.0/gix/src/repository/submodule.rs) reads that path with `std::fs::read(&path)` and immediately parses the bytes as a submodule configuration file.
3. `Repository::submodules()` exposes the parsed entries through the high-level API.

The issue is not in the parser. The issue is that the worktree path is treated as an ordinary file without checking whether it is a symlink, and without checking whether the canonicalized target remains inside the repository worktree.

Because `std::fs::read()` follows symlinks, a malicious repository can cause gitoxide to ingest bytes from an attacker-chosen location outside the repository. The resulting `Submodule` objects then expose `name`, `path`, and `url` values derived from that external file.

## Reproduction steps

Use the attached PoC zip that contains the `pocs/` workspace.

1. Unzip the PoC archive.
2. Enter `pocs/F001`.
3. Run:
    
    ```bash
    cargo run --quiet
    ```
    
4. Compare the output with `pocs/F001/result.txt`.

Important outputs include:

- `gitmodules_symlink=.../victim-repo/.gitmodules`
- `symlink_target=.../outside/modules.conf`
- `parsed_name=symlinked`
- `parsed_path=deps/symlinked`
- `parsed_url=https://attacker.example/symlinked.git`

These outputs show that gitoxide parsed the submodule configuration from the symlink target outside the repository, not from repository-local bytes.

## Impact

Confirmed impact:

- out-of-repository bytes can be injected into the result of `Repository::submodules()`;
- callers can be misled about submodule metadata such as `name`, `path`, and `url`;
- any downstream workflow that uses those values to decide clone, fetch, update, or policy behavior is operating on attacker-controlled data that did not actually originate from the repository tree.

This report does **not** claim direct command execution from this code path by itself. The demonstrated impact is metadata injection across the repository boundary.

## Recommended fix

A safe fix is to stop silently following symlinks for the worktree `.gitmodules` path in this loading path.

Reasonable options include:

1. use `symlink_metadata()` / `lstat`style checks and reject symlinked `.gitmodules` when loading from the worktree;
2. canonicalize the target and verify that it still resides under the repository worktree before reading it;
3. for security-sensitive callers, prefer loading `.gitmodules` from the index or `HEAD` tree rather than following the worktree path.

At minimum, the worktree path should not silently follow symlinks to arbitrary external files.

## Affected packages

- `gitoxide < 0.52.1`
- `gix < 0.83.0`

## Remediation

Upgrade to a patched release:

- `gitoxide 0.52.1`
- `gix 0.83.0`
