Gitoxide (gix), Submodule Update Command Injection, (No CVE – Critical)

Listen to this Post

How the mentioned CVE works (approx. 20 lines):

The vulnerability resides in gix_submodule::File::update(), which determines if a submodule’s `update` value from `.gitmodules` can be a shell command (e.g., update = !touch /tmp/pwned). The API intends to return `Err(CommandForbiddenInModulesConfiguration)` unless the command originates from a trusted source like .git/config. However, the guard is flawed: it checks whether any section with the submodule name exists from a non-.gitmodules source, but does not verify that the actual `update` value came from that trusted section.
An attacker first supplies a benign `.gitmodules` (no `update` key). The victim runs git submodule init, which writes `url` and `active = true` into `.git/config` – without copying any `update` key. Later, the attacker pushes a malicious commit that adds `update = !cmd` to .gitmodules. The victim pulls this change. Now `.git/config` has a trusted section (with only `url` and active), while `.gitmodules` has the attacker’s command.
When `gix::Submodule::update()` is called, the lookup reads `submodule..update` by scanning sections newest-to-oldest. The trusted `.git/config` section lacks an `update` key, so the lookup falls through to `.gitmodules` and returns the command. The guard sees that a trusted section exists (even without the key) and therefore allows the command – bypassing the intended restriction.
In contrast, `git submodule update` on the same repository aborts with fatal: invalid value for 'submodule.sub.update'. The vulnerable code was introduced in commit 6a2e6a4. Any downstream application that calls `Submodule::update()` and trusts `Update::Command` as safe is vulnerable to arbitrary command execution.

DailyCVE form:

Platform: Gitoxide library
Version: before patch
Vulnerability: Submodule update bypass
Severity: Critical
date: 2025-04-07

Prediction: 2025-05-15

Analytics under What Undercode Say:

Unit test confirming bypass
cargo test -p gix-submodule security_bypass -- --nocapture
End-to-end reproduction
git clone /tmp/evil-repo victim
cd victim && git submodule init
cd ../evil-repo && echo 'update = !touch /tmp/pwned' >> .gitmodules
git commit -am "malicious"
cd ../victim && git pull
cargo run --bin show_submodule_update
// Vulnerable code snippet (access.rs lines 168-193)
let value: Update = self.config.string(format!("submodule.{name}.update"))?;
if let Update::Command(cmd) = &value {
let has_value_from_foreign_section = self.config.sections_by_name("submodule")
.into_iter().flatten()
.any(|s| s.header().subsection_name() == Some(name) && !std::ptr::eq(s.meta(), ours));
if !has_value_from_foreign_section { return Err(CommandForbidden...); }
}

Exploit:

Attacker needs a repository with a submodule that the victim has initialized once (e.g., via git submodule init). After victim runs init, attacker adds `update = !malicious_command` to `.gitmodules` and pushes. Victim pulls. Any tool using `gix::Submodule::update()` will then return Ok(Some(Update::Command("malicious_command"))), leading to RCE when that command is executed.

Protection from this CVE:

  • Upgrade gix/gitoxide to a patched version once available (fixes should compare the source of the `update` value, not just existence of any trusted section).
  • Avoid calling `Submodule::update()` on submodules that have ever been initialized from untrusted remotes.
  • Use `git` CLI instead of gitoxide for submodule operations until patch is applied.
  • Implement manual validation: after obtaining Update, check whether the effective value originates from `.git/config` by re-reading from specific origin.

Impact:

Direct: Any downstream application (CI integrations, IDE plugins, forge tools) using `gix` that relies on `Submodule::update()` and then executes the returned command will suffer arbitrary shell command injection. Indirect: Tools that implement their own `init` (writing `url` to .git/config) create the vulnerable state without needing a `pull` sequence. The `gix` CLI itself is not directly exploitable because it lacks a submodule update command, but the public API is exposed and documented as secure.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top