From 14e7c50478942d00f76379671089159dc9382fe6 Mon Sep 17 00:00:00 2001 From: Brian Donovan <1938+eventualbuddha@users.noreply.github.com> Date: Fri, 4 Aug 2023 20:02:07 -0700 Subject: [PATCH] fix(cli): prevent "zip slip" vulnerability in tool extract Using the name directly from a zip archive's entry and writing to it is a potential security vulnerability. More information about the vulnerability can be found here: https://security.snyk.io/research/zip-slip-vulnerability and here https://docs.rs/zip/latest/zip/read/struct.ZipFile.html#warnings. It looks like the previous version maybe tried to remove `\` characters to prevent this, but only in directory paths? --- packages/cli/src/tools.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/tools.rs b/packages/cli/src/tools.rs index 98d4f9dbe..b1fcdc72d 100644 --- a/packages/cli/src/tools.rs +++ b/packages/cli/src/tools.rs @@ -328,20 +328,26 @@ pub fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> { } for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - if file.is_dir() { + let mut zip_entry = zip.by_index(i)?; + let Some(enclosed_name) = zip_entry.enclosed_name() else { + return Err(anyhow::anyhow!( + "Refusing to unpack zip entry with potentially dangerous path: zip={} entry={:?}", + file.display(), + zip_entry.name() + )); + }; + let output_path = target.join(enclosed_name); + if zip_entry.is_dir() { // dir - let target = target.join(Path::new(&file.name().replace('\\', ""))); - std::fs::create_dir_all(target)?; + std::fs::create_dir_all(output_path)?; } else { // file - let file_path = target.join(Path::new(file.name())); - let mut target_file = if !file_path.exists() { - std::fs::File::create(file_path)? + let mut target_file = if !output_path.exists() { + std::fs::File::create(output_path)? } else { - std::fs::File::open(file_path)? + std::fs::File::open(output_path)? }; - let _num = std::io::copy(&mut file, &mut target_file)?; + let _num = std::io::copy(&mut zip_entry, &mut target_file)?; } }