{"id":"RUSTSEC-2026-0431","aliases":[],"status":"published","title":"Unbounded memory allocation in `evtx` parsing a `.wevtcache` file","description":"Affected versions of `evtx` did not bound a per-entry payload length read from a `.wevtcache` file before allocating a buffer sized from it, allowing a tiny crafted file to force a multi-gigabyte allocation and abort the process (out-of-memory denial of service, CWE-400).\n\n## Details\n\nIn `WevtCacheReader::next_entry` (`src/wevt_templates/wevtcache.rs`), the per-entry payload length is read as a `u64` straight from the file and used to size a zeroing buffer **before** any data is read:\n\n```rust\nlet len = usize::try_from(len_u64)?;   // u64 taken directly from the entry header\nlet mut buf = vec![0u8; len];          // unbounded allocation, sized from the file\nreader.read_exact(\u0026mut buf)?;          // only fails AFTER the allocation\n```\n\nThe only check on `len` is that it fits in `usize`; there is no check that it fits within the bytes remaining in the file. An entry header declaring a ~4 GiB length therefore makes the crate request a ~4 GiB allocation from a file of only ~25 bytes.\n\nThe sink is reachable through the public API `evtx::wevt_templates::wevtcache::for_each_crim_blob(path, f)` (and the `WevtCacheReader::next_entry` it drives). The `.wevtcache` reader first shipped in `0.11.0`, and every published version from `0.11.0` through `0.14.0` is affected. The code lives in the `wevt_templates` feature, which is enabled by default through the `evtx_dump` feature. The fix landed in `0.15.1`: `0.15.0` was tagged but never published to crates.io (its Windows build failed), so `0.15.1` is the first patched release available. The Python bindings (`evtx` on PyPI) carry the fix as of `0.15.0`.\n\n## Reproduction\n\nA ~25-byte file is sufficient: the `.wevtcache` magic (`WEVTCACH`), a `version` (u32 LE) of `1`, an `entry_count` (u32 LE) of `1`, then one entry consisting of a `kind` byte and a `len` (u64 LE) set to a large value (e.g. `0xFFFFFFF0`), with no payload bytes following. Passing that file to `for_each_crim_blob` triggers the oversized allocation before the short read fails.","severity":{"version":"3.1","score":5.5,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H","level":"medium","from":"osv"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"published":"2026-11-01T12:00:00Z","modified":"2026-11-02T11:00:02Z","fixes":[{"ecosystem":"crates.io","package":"evtx","fixed_in":["0.15.1"],"sources":["osv"]}],"affected":[{"source":"osv","ecosystem":"crates.io","package":"evtx","ranges":[{"type":"SEMVER","events":[{"introduced":"0.11.0"},{"fixed":"0.15.1"}]}]}],"references":[{"url":"https://crates.io/crates/evtx","tags":["package"]},{"url":"https://rustsec.org/advisories/RUSTSEC-2026-0431.html","tags":["advisory"]},{"url":"https://github.com/omerbenamram/evtx/issues/334","tags":["report"]},{"url":"https://github.com/omerbenamram/evtx/pull/335","tags":["web"]}],"sources":{"osv":[{"id":"RUSTSEC-2026-0431","title":"Unbounded memory allocation in `evtx` parsing a `.wevtcache` file","description":"Affected versions of `evtx` did not bound a per-entry payload length read from a `.wevtcache` file before allocating a buffer sized from it, allowing a tiny crafted file to force a multi-gigabyte allocation and abort the process (out-of-memory denial of service, CWE-400).\n\n## Details\n\nIn `WevtCacheReader::next_entry` (`src/wevt_templates/wevtcache.rs`), the per-entry payload length is read as a `u64` straight from the file and used to size a zeroing buffer **before** any data is read:\n\n```rust\nlet len = usize::try_from(len_u64)?;   // u64 taken directly from the entry header\nlet mut buf = vec![0u8; len];          // unbounded allocation, sized from the file\nreader.read_exact(\u0026mut buf)?;          // only fails AFTER the allocation\n```\n\nThe only check on `len` is that it fits in `usize`; there is no check that it fits within the bytes remaining in the file. An entry header declaring a ~4 GiB length therefore makes the crate request a ~4 GiB allocation from a file of only ~25 bytes.\n\nThe sink is reachable through the public API `evtx::wevt_templates::wevtcache::for_each_crim_blob(path, f)` (and the `WevtCacheReader::next_entry` it drives). The `.wevtcache` reader first shipped in `0.11.0`, and every published version from `0.11.0` through `0.14.0` is affected. The code lives in the `wevt_templates` feature, which is enabled by default through the `evtx_dump` feature. The fix landed in `0.15.1`: `0.15.0` was tagged but never published to crates.io (its Windows build failed), so `0.15.1` is the first patched release available. The Python bindings (`evtx` on PyPI) carry the fix as of `0.15.0`.\n\n## Reproduction\n\nA ~25-byte file is sufficient: the `.wevtcache` magic (`WEVTCACH`), a `version` (u32 LE) of `1`, an `entry_count` (u32 LE) of `1`, then one entry consisting of a `kind` byte and a `len` (u64 LE) set to a large value (e.g. `0xFFFFFFF0`), with no payload bytes following. Passing that file to `for_each_crim_blob` triggers the oversized allocation before the short read fails.","status":"published","published":"2026-11-01T12:00:00Z","modified":"2026-11-02T11:00:02.238924591Z","cvss":[{"version":"3.1","score":5.5,"vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T15:53:40.430679Z"}]}}
