Environment: curl 8.22.0 on Linux (also reproduced on current master). CLI tool only.
What happens
--output-dir is supposed to keep all downloads inside the given directory, but if the output
filename comes from a URL glob via -o "#N" (or #<name>), the substituted glob match is used
as-is and can walk out of the directory.
Repro
Serve anything on http://127.0.0.1:8080/, then:
$ mkdir -p work/out && cd work
$ curl --output-dir out -o "#1" "http://127.0.0.1:8080/files/{a,../escaped}"
$ ls out
a
$ ls -l escaped # created in work/, outside out/
The glob produces http://127.0.0.1:8080/files/a and .../files/../escaped; for the second one the
#1 reference substitutes the raw match ../escaped and the file ends up at out/../escaped.
Why
setup_outfile() just concatenates: curl_maprintf("%s/%s", output_dir, per->outfile).
glob_match_url() substitutes the raw glob match into the output name; on non-Windows there is no
sanitization of / or .. (only _WIN32/MSDOS builds sanitize, with SANITIZE_ALLOW_PATH anyway).
-O is fine because the name comes from the last URL path segment and the URL API normalizes /dir/...
Expected vs actual
Expected: files stay inside --output-dir. Actual: file written outside it (path-isolation /
file-integrity issue). Relevant when the URL/glob comes from untrusted input combined with
--output-dir + -o "#N".
A fix could reject or neutralize / and .. in glob-referenced output names, like -O is limited to
a single path component.
Environment: curl 8.22.0 on Linux (also reproduced on current master). CLI tool only.
What happens
--output-diris supposed to keep all downloads inside the given directory, but if the outputfilename comes from a URL glob via
-o "#N"(or#<name>), the substituted glob match is usedas-is and can walk out of the directory.
Repro
Serve anything on
http://127.0.0.1:8080/, then:The glob produces
http://127.0.0.1:8080/files/aand.../files/../escaped; for the second one the#1reference substitutes the raw match../escapedand the file ends up atout/../escaped.Why
setup_outfile()just concatenates:curl_maprintf("%s/%s", output_dir, per->outfile).glob_match_url()substitutes the raw glob match into the output name; on non-Windows there is nosanitization of
/or..(only_WIN32/MSDOS builds sanitize, withSANITIZE_ALLOW_PATHanyway).-Ois fine because the name comes from the last URL path segment and the URL API normalizes/dir/...Expected vs actual
Expected: files stay inside
--output-dir. Actual: file written outside it (path-isolation /file-integrity issue). Relevant when the URL/glob comes from untrusted input combined with
--output-dir+-o "#N".A fix could reject or neutralize
/and..in glob-referenced output names, like-Ois limited toa single path component.