VYPR
Critical severityNVD Advisory· Published Aug 26, 2019· Updated Aug 5, 2024

CVE-2019-15552

CVE-2019-15552

Description

Use-after-free in libflate's MultiDecoder::read allows arbitrary code execution; fixed in v0.1.25.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Use-after-free in libflate's MultiDecoder::read allows arbitrary code execution; fixed in v0.1.25.

CVE-2019-15552 is a use-after-free vulnerability in the MultiDecoder::read method of the libflate crate for Rust, affecting versions before 0.1.25. The root cause is the use of mem::replace with mem::uninitialized() to swap out the decoder, which can drop uninitialized memory of arbitrary type if a panic occurs in client code, leading to undefined behavior [1][2].

Exploitation requires no authentication and can be performed over the network with low complexity (CVSS 3.0 score 9.8). An attacker can trigger the vulnerability by crafting malicious input that causes the decoder to panic during reading, forcing the drop of uninitialized memory [2].

Successful exploitation could allow an attacker to execute arbitrary code with the privileges of the process using the library, potentially leading to full system compromise [1][2].

The issue has been patched in libflate version 0.1.25 and later. Users should upgrade to the latest version to mitigate the risk. The fix replaces the unsafe mem::replace block with the take_mut crate, ensuring safe handling of panics [3].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
libflatecrates.io
>= 0.1.14, < 0.1.250.1.25

Affected products

2

Patches

1
ffeff7c65dea

Use take_mut instead of a bespoke unsafe block with mem::replace

https://github.com/sile/libflateSergey "Shnatsel" DavidoffJun 29, 2019via ghsa
3 files changed · +28 23
  • Cargo.toml+1 0 modified
    @@ -18,6 +18,7 @@ codecov = {repository = "sile/libflate"}
     adler32 = "1"
     byteorder = "1"
     crc32fast = "1"
    +take_mut = "0.2.2"
     
     [dev-dependencies]
     clap = "2"
    
  • src/gzip.rs+26 23 modified
    @@ -24,7 +24,6 @@ use byteorder::ReadBytesExt;
     use byteorder::WriteBytesExt;
     use std::ffi::CString;
     use std::io;
    -use std::mem;
     use std::time;
     
     use checksum;
    @@ -1118,33 +1117,37 @@ where
                 Err(_) => return Ok(0),
                 Ok(ref mut decoder) => decoder.read(buf)?,
             };
    +        // take_mut closure must have the type it borrows as return type,
    +        // so we put the function return result to this variable instead.
    +        // If function logic is correct, these initial values will never be returned.
    +        let mut result: io::Result<usize> = Err(
    +            io::Error::new(io::ErrorKind::Other, "If you see this error, please report a bug in libflate")
    +        );
             if read_size == 0 {
    -            let mut reader = mem::replace(&mut self.decoder, Err(unsafe { mem::uninitialized() }))
    -                .ok()
    -                .take()
    -                .expect("Never fails")
    -                .into_inner();
    -            match Header::read_from(&mut reader) {
    -                Err(e) => {
    -                    mem::forget(mem::replace(&mut self.decoder, Err(reader)));
    -                    if e.kind() == io::ErrorKind::UnexpectedEof {
    -                        Ok(0)
    -                    } else {
    -                        Err(e)
    +            take_mut::take(self, |mut owned_self| {
    +                let mut reader = owned_self.decoder.ok().take().expect("Never fails").into_inner();
    +                match Header::read_from(&mut reader) {
    +                    Err(e) => {
    +                        if e.kind() == io::ErrorKind::UnexpectedEof {
    +                            result = Ok(0);
    +                        } else {
    +                            result = Err(e);
    +                        }
    +                        owned_self.decoder = Err(reader);
    +                        owned_self
    +                    }
    +                    Ok(header) => {
    +                        owned_self.header = header.clone();
    +                        owned_self.decoder = Ok(Decoder::with_header(reader, header));
    +                        result = owned_self.read(buf);
    +                        owned_self
                         }
                     }
    -                Ok(header) => {
    -                    self.header = header.clone();
    -                    mem::forget(mem::replace(
    -                        &mut self.decoder,
    -                        Ok(Decoder::with_header(reader, header)),
    -                    ));
    -                    self.read(buf)
    -                }
    -            }
    +            })
             } else {
    -            Ok(read_size)
    +            result = Ok(read_size);
             }
    +        result
         }
     }
     
    
  • src/lib.rs+1 0 modified
    @@ -3,6 +3,7 @@
     extern crate adler32;
     extern crate byteorder;
     extern crate crc32fast;
    +extern crate take_mut;
     
     pub use finish::Finish;
     
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.