{"id":"CVE-2026-82253","aliases":["GHSA-p3hw-mv63-rf9w"],"title":"gix's submodule name validation bypass + trust inheritance flaw enables path traversal and credential disclosure","summary":"gix's submodule name validation bypass + trust inheritance flaw enables path traversal and credential disclosure","severity":"high","vendor":"gix","product":"gix","ecosystem":"rust","affected":["gix < 0.83.0","gix-validate < 0.11.1"],"patched":["gix 0.83.0","gix-validate 0.11.1"],"published":"2026-05-05","updated":"2026-08-29","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-p3hw-mv63-rf9w","references":[{"url":"https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-p3hw-mv63-rf9w"},{"url":"https://github.com/GitoxideLabs/gitoxide"}],"tags":["osv","rust"],"epss":0.00497,"epssPercentile":0.41681,"ingestedAt":"2026-08-29T19:29:15.797Z","slug":"CVE-2026-82253","body":"## Overview\n\n### Summary\n\nSubmodule name validation bypass plus missing validation in production code paths allows path traversal via crafted `.gitmodules`. Combined with a trust inheritance flaw in `Submodule::open()`, this enables reading arbitrary git repository configs (including credentials) from traversed paths with full trust (CWE-22, CWE-200).\n\n### Details\n\n**Bug 1: Validation bypass in `gix-validate/src/submodule.rs` (lines 27-42)**\n\nThe `name()` function uses `name.find(b\"..\")` which returns only the FIRST occurrence. If the first `..` is embedded in a non-traversal context, the function returns `Ok` without checking subsequent `../` sequences:\n\n```rust\npub fn name(name: &BStr) -> Result<&BStr, name::Error> {\n    match name.find(b\"..\") {\n        Some(pos) => {\n            let &b = name.get(pos + 2).ok_or(name::Error::ParentComponent)?;\n            if b == b'/' || b == b'\\\\' {\n                Err(name::Error::ParentComponent)\n            } else {\n                Ok(name)  // Returns Ok without checking rest of string\n            }\n        }\n        None => Ok(name),\n    }\n}\n```\n\nBypass: `a..b/../../../.git/` passes because `find(b\"..\")` returns position 1 (the `..` in `a..b`), checks `name[3] == b'b'`, and returns Ok. The real `/../../../` is never checked.\n\n**Bug 2: Validation never called in production**\n\n`gix_validate::submodule::name()` has zero production callers (only test code). The `names()` iterator in `gix-submodule/src/access.rs:29` explicitly documents it returns \"unvalidated names.\"\n\n`git_dir()` at `gix/src/submodule/mod.rs:198-204` constructs filesystem paths from raw names:\n\n```rust\npub fn git_dir(&self) -> PathBuf {\n    self.state.repo.common_dir().join(\"modules\").join(gix_path::from_bstr(self.name()))\n}\n```\n\n**Bug 3: Trust inheritance bypass in `Submodule::open()`**\n\nAt `gix/src/submodule/mod.rs:270`, `open()` clones the parent repository's options:\n\n```rust\nmatch crate::open_opts(self.git_dir_try_old_form()?, self.state.repo.options.clone()) {\n```\n\nThe parent's `options.git_dir_trust` is `Some(Trust::Full)`. At `gix/src/open/repository.rs:103-104`:\n\n```rust\nif options.git_dir_trust.is_none() {\n    options.git_dir_trust = gix_sec::Trust::from_path_ownership(&git_dir)?.into();\n}\n```\n\nSince trust is already `Some(Full)`, the ownership check is **skipped entirely**. The traversed path is opened with `Trust::Full` regardless of ownership, bypassing gitoxide's safe-directory protections.\n\n### PoC\n\nCompiled and executed in Rust 1.94.1 `--release` mode. All bypass cases confirmed:\n\n```\nBYPASS a..b/../../../.git/           -> PASSED validation\n       git_dir = .git/modules/a..b/../../../.git/\n       normalized = .git/              (parent repo!)\n\nBYPASS x..y/../../../.git/config     -> PASSED validation\n       git_dir = .git/modules/x..y/../../../.git/config\n       normalized = .git/config\n```\n\n### Attack chain\n\n1. Attacker crafts a repository with `.gitmodules`:\n   ```ini\n   [submodule \"x..y/../../..\"]\n       path = innocent\n       url = https://attacker.com/repo.git\n   ```\n\n2. Victim clones the repository using a tool built on gitoxide.\n\n3. When the tool iterates submodules and calls `submodule.open()` or `submodule.status()`:\n   - `git_dir()` returns `.git/modules/x..y/../../..` which resolves to the parent `.git/`\n   - `open_opts()` is called with `Trust::Full` (inherited from parent, ownership check skipped)\n   - The parent's `.git/config` is fully parsed\n\n4. The returned `Repository` object exposes all config values from the traversed path:\n   - `remote.origin.url` (may contain `https://user:token@github.com/...`)\n   - `http.extraHeader` (often `Authorization: Bearer <token>`)\n   - `credential.*` sections\n   - `core.sshCommand`\n\n5. Accessible via standard API: `repo.config_snapshot().string(\"http.extraHeader\")`, `repo.find_remote(\"origin\")`, etc.\n\n### Impact\n\nA crafted `.gitmodules` in a malicious repository causes gitoxide to open arbitrary git directories as submodule repositories with full trust, exposing their configuration including credentials. This is the same class of vulnerability as GHSA-7w47-3wg8-547c (path traversal), but through the submodule name vector with an additional trust bypass.\n\nThe trust inheritance is the critical amplifier: without it, the traversed path would undergo ownership checks that could block the attack. With it, any git directory reachable via `../` is opened with full trust.\n\n### Honest limitations\n\n- The traversed path must be a valid git directory (HEAD, objects/, refs/ must exist)\n- The victim's tool must call `open()` or `status()` on submodules (tools that only list submodules are not affected)\n- Credential exposure requires the target config to contain embedded credentials\n- Submodule operations currently require explicit user action\n\n### Suggested fix\n\n1. Fix the validation to check ALL `..` occurrences (iterate, not single `find`)\n2. Call `gix_validate::submodule::name()` in `git_dir()` before constructing the path\n3. Do NOT inherit `git_dir_trust` from parent when opening submodule repos -- always re-derive trust from path ownership\n\n### Severity\n\nHigh. Network vector (via clone), requires user interaction (submodule operations). The trust bypass enables credential disclosure from traversed git directories. Confidentiality impact is high.\n\n## Affected packages\n\n- `gix < 0.83.0`\n- `gix-validate < 0.11.1`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `gix 0.83.0`\n- `gix-validate 0.11.1`","depth":"twilight","depthScore":41,"depthScoreParts":{"impact":41.3,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}