Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package xh for openSUSE:Factory checked in at 2024-07-11 20:29:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xh (Old) and /work/SRC/openSUSE:Factory/.xh.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xh" Thu Jul 11 20:29:56 2024 rev:5 rq:1186517 version:0.22.2~0 Changes: -------- --- /work/SRC/openSUSE:Factory/xh/xh.changes 2024-04-15 20:24:15.221422668 +0200 +++ /work/SRC/openSUSE:Factory/.xh.new.17339/xh.changes 2024-07-11 20:30:18.850562419 +0200 @@ -1,0 +2,6 @@ +Wed Jul 10 06:57:13 UTC 2024 - Michael Vetter <mvet...@suse.com> + +- Update to 0.22.2: + * Prevent directory traversal in server-supplied filenames #379 + +------------------------------------------------------------------- Old: ---- xh-0.22.0~0.tar.xz New: ---- xh-0.22.2~0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xh.spec ++++++ --- /var/tmp/diff_new_pack.8OvpmI/_old 2024-07-11 20:30:19.726594793 +0200 +++ /var/tmp/diff_new_pack.8OvpmI/_new 2024-07-11 20:30:19.730594941 +0200 @@ -17,7 +17,7 @@ Name: xh -Version: 0.22.0~0 +Version: 0.22.2~0 Release: 0 Summary: Tool for sending HTTP requests License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.8OvpmI/_old 2024-07-11 20:30:19.766596272 +0200 +++ /var/tmp/diff_new_pack.8OvpmI/_new 2024-07-11 20:30:19.766596272 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/ducaale/xh</param> <param name="versionformat">@PARENT_TAG@~@TAG_OFFSET@</param> <param name="scm">git</param> - <param name="revision">v0.22.0</param> + <param name="revision">v0.22.2</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="versionrewrite-replacement">\1</param> ++++++ vendor.tar.xz ++++++ /work/SRC/openSUSE:Factory/xh/vendor.tar.xz /work/SRC/openSUSE:Factory/.xh.new.17339/vendor.tar.xz differ: char 15, line 1 ++++++ xh-0.22.0~0.tar.xz -> xh-0.22.2~0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/.github/workflows/ci.yaml new/xh-0.22.2~0/.github/workflows/ci.yaml --- old/xh-0.22.0~0/.github/workflows/ci.yaml 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/.github/workflows/ci.yaml 2024-07-09 00:16:09.000000000 +0200 @@ -22,7 +22,7 @@ os: ubuntu-latest flags: --no-default-features --features=native-tls,online-tests # disables rustls - target: x86_64-apple-darwin - os: macos-latest + os: macos-13 flags: --features=native-tls - target: aarch64-apple-darwin os: macos-14 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/.github/workflows/release.yaml new/xh-0.22.2~0/.github/workflows/release.yaml --- old/xh-0.22.0~0/.github/workflows/release.yaml 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/.github/workflows/release.yaml 2024-07-09 00:16:09.000000000 +0200 @@ -19,7 +19,7 @@ os: ubuntu-latest flags: --no-default-features --features=native-tls,online-tests # disables rustls - target: x86_64-apple-darwin - os: macos-latest + os: macos-13 flags: --features=native-tls - target: aarch64-apple-darwin os: macos-14 @@ -70,7 +70,7 @@ - os: ubuntu-latest target: x86_64-unknown-linux-musl use-cross: true - - os: macos-latest + - os: macos-13 target: x86_64-apple-darwin flags: --features=native-tls - os: macos-14 @@ -127,7 +127,7 @@ if [ "${{ matrix.job.os }}" = "windows-latest" ]; then 7z a "$staging.zip" $staging - elif [ "${{ matrix.job.os }}" = "macos-latest" ]; then + elif [[ "${{ matrix.job.os }}" =~ "macos" ]]; then gtar czvf "$staging.tar.gz" $staging else tar czvf "$staging.tar.gz" $staging diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/CHANGELOG.md new/xh-0.22.2~0/CHANGELOG.md --- old/xh-0.22.0~0/CHANGELOG.md 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/CHANGELOG.md 2024-07-09 00:16:09.000000000 +0200 @@ -1,3 +1,7 @@ +## [0.22.2] - 2024-07-08 +### Security fixes +- Prevent directory traversal in server-supplied filenames, see #379 (@blyxxyz) + ## [0.22.0] - 2024-04-13 ### Features - Support http2-prior-knowledge, see #356 (@zuisong) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/Cargo.lock new/xh-0.22.2~0/Cargo.lock --- old/xh-0.22.0~0/Cargo.lock 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/Cargo.lock 2024-07-09 00:16:09.000000000 +0200 @@ -2383,7 +2383,7 @@ [[package]] name = "xh" -version = "0.22.0" +version = "0.22.2" dependencies = [ "anyhow", "assert_cmd", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/Cargo.toml new/xh-0.22.2~0/Cargo.toml --- old/xh-0.22.0~0/Cargo.toml 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/Cargo.toml 2024-07-09 00:16:09.000000000 +0200 @@ -1,6 +1,6 @@ [package] name = "xh" -version = "0.22.0" +version = "0.22.2" authors = ["ducaale <sharaf...@hotmail.com>"] edition = "2021" rust-version = "1.74.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/doc/xh.1 new/xh-0.22.2~0/doc/xh.1 --- old/xh-0.22.0~0/doc/xh.1 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/doc/xh.1 2024-07-09 00:16:09.000000000 +0200 @@ -1,4 +1,4 @@ -.TH XH 1 2024-04-12 0.22.0 "User Commands" +.TH XH 1 2024-07-08 0.22.2 "User Commands" .SH NAME xh \- Friendly and fast tool for sending HTTP requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/src/download.rs new/xh-0.22.2~0/src/download.rs --- old/xh-0.22.0~0/src/download.rs 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/src/download.rs 2024-07-09 00:16:09.000000000 +0200 @@ -28,8 +28,9 @@ fn get_file_name(response: &Response, orig_url: &reqwest::Url) -> String { fn from_header(response: &Response) -> Option<String> { let quoted = Regex::new("filename=\"([^\"]*)\"").unwrap(); - // Against the spec, but used by e.g. Github's zip downloads + // Alternative form: let unquoted = Regex::new("filename=([^;=\"]*)").unwrap(); + // TODO: support "filename*" version let header = response.headers().get(CONTENT_DISPOSITION)?.to_str().ok()?; let caps = quoted @@ -51,11 +52,13 @@ mime2ext(mimetype) } - let mut filename = from_header(response) + let filename = from_header(response) .or_else(|| from_url(orig_url)) .unwrap_or_else(|| "index".to_string()); - filename = filename.trim().trim_start_matches('.').to_string(); + let filename = filename.split(std::path::is_separator).last().unwrap(); + + let mut filename = filename.trim().trim_start_matches('.').to_string(); if !filename.contains('.') { if let Some(extension) = guess_extension(response) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/src/request_items.rs new/xh-0.22.2~0/src/request_items.rs --- old/xh-0.22.0~0/src/request_items.rs 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/src/request_items.rs 2024-07-09 00:16:09.000000000 +0200 @@ -220,6 +220,7 @@ File { file_name: PathBuf, file_type: Option<HeaderValue>, + #[allow(dead_code)] file_name_header: Option<String>, }, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xh-0.22.0~0/tests/cli.rs new/xh-0.22.2~0/tests/cli.rs --- old/xh-0.22.0~0/tests/cli.rs 2024-04-13 00:34:00.000000000 +0200 +++ new/xh-0.22.2~0/tests/cli.rs 2024-07-09 00:16:09.000000000 +0200 @@ -551,6 +551,49 @@ ); } +#[test] +fn download_filename_with_directory_traversal() { + let dir = tempdir().unwrap(); + let server = server::http(|_req| async move { + hyper::Response::builder() + .header( + "Content-Disposition", + r#"attachment; filename="foo/baz/bar""#, + ) + .body("file".into()) + .unwrap() + }); + + get_command() + .args(["--download", &server.base_url()]) + .current_dir(&dir) + .assert() + .success(); + assert_eq!(fs::read_to_string(dir.path().join("bar")).unwrap(), "file"); +} + +#[cfg(windows)] +#[test] +fn download_filename_with_windows_directory_traversal() { + let dir = tempdir().unwrap(); + let server = server::http(|_req| async move { + hyper::Response::builder() + .header( + "Content-Disposition", + r#"attachment; filename="foo\baz\bar""#, + ) + .body("file".into()) + .unwrap() + }); + + get_command() + .args(["--download", &server.base_url()]) + .current_dir(&dir) + .assert() + .success(); + assert_eq!(fs::read_to_string(dir.path().join("bar")).unwrap(), "file"); +} + // TODO: test implicit download filenames // For this we have to pretend the output is a tty // This intersects with both #41 and #59