{"id":"RUSTSEC-2026-0403","aliases":[],"status":"published","title":"Uninitialized memory exposed when streaming decompression of a legacy frame fails","description":"When decompression fails inside a legacy (zstd v0.4 to v0.7) frame, the\nbundled zstd library reports the output buffer as fully written although\nnothing was written. `DCtx::decompress_stream` committed that position even\non error, and for a `Vec\u003cu8\u003e` destination this extended the vector's length\nover uninitialized memory.\n\nLegacy support is enabled by default. A 5- or 6-byte corrupt legacy frame is\nenough: through `zstd::stream::write::Decoder`, up to 32 KiB of stale heap\nmemory is then passed to the wrapped writer on the next `write()` or\n`flush()`, or when an `auto_flush()`/`on_flush()` decoder is dropped. Whether\nthis reaches an attacker depends on where the application sends the\ndecompressed output. `zstd::stream::read::Decoder`, `zstd::decode_all` and\nthe bulk API are not affected.\n\nBefore zstd-safe 4.0.0, output buffers could only be initialized slices.\nThe zstd crate's own writer had the same flaw from 0.4.22 to 0.7.x, which is\ncovered by a separate advisory.\n\nThe flaw was corrected by only committing the buffer positions of a\nsuccessful call.","facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"published":"2026-10-16T12:00:00Z","modified":"2026-11-02T09:30:04Z","fixes":[{"ecosystem":"crates.io","package":"zstd-safe","fixed_in":["7.4.0","8.2.0"],"sources":["osv"]}],"affected":[{"source":"osv","ecosystem":"crates.io","package":"zstd-safe","ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0"},{"fixed":"7.4.0"},{"introduced":"8.0.0-0"},{"fixed":"8.2.0"}]}]}],"references":[{"url":"https://crates.io/crates/zstd-safe","tags":["package"]},{"url":"https://rustsec.org/advisories/RUSTSEC-2026-0403.html","tags":["advisory"]},{"url":"https://github.com/gyscos/zstd-rs/commit/006e1d1ad1eeaf6b5d4c28329e70217adabcec43","tags":["web"]},{"url":"https://github.com/gyscos/zstd-rs/pull/384","tags":["web"]}],"sources":{"osv":[{"id":"RUSTSEC-2026-0403","title":"Uninitialized memory exposed when streaming decompression of a legacy frame fails","description":"When decompression fails inside a legacy (zstd v0.4 to v0.7) frame, the\nbundled zstd library reports the output buffer as fully written although\nnothing was written. `DCtx::decompress_stream` committed that position even\non error, and for a `Vec\u003cu8\u003e` destination this extended the vector's length\nover uninitialized memory.\n\nLegacy support is enabled by default. A 5- or 6-byte corrupt legacy frame is\nenough: through `zstd::stream::write::Decoder`, up to 32 KiB of stale heap\nmemory is then passed to the wrapped writer on the next `write()` or\n`flush()`, or when an `auto_flush()`/`on_flush()` decoder is dropped. Whether\nthis reaches an attacker depends on where the application sends the\ndecompressed output. `zstd::stream::read::Decoder`, `zstd::decode_all` and\nthe bulk API are not affected.\n\nBefore zstd-safe 4.0.0, output buffers could only be initialized slices.\nThe zstd crate's own writer had the same flaw from 0.4.22 to 0.7.x, which is\ncovered by a separate advisory.\n\nThe flaw was corrected by only committing the buffer positions of a\nsuccessful call.","status":"published","published":"2026-10-16T12:00:00Z","modified":"2026-11-02T09:30:04.136442771Z","updated_at":"2026-11-02T15:53:40.430679Z"}]}}
