HexBrain

curl · Report #4057637

[HIGH] CWE-22 — Path Traversal in FTP Wildcard Download via Unencoded `.` in Escaped Filenames

Informativestatus
highseverity
54upvotes
26 Sept 2026disclosed

How it was found

Summary

A malicious or MITM'd FTP server can cause a client using CURLOPT_WILDCARDMATCH to download files outside the intended remote directory, by returning a LIST response with a filename containing .. path-traversal sequences.

Details

In the CURLWC_DOWNLOADING state (lib/ftp.c:4079-4095), each filename returned by the server's LIST response is escaped with curl_easy_escape() before being appended to the current wildcard path:

`char *enc = curl_easy_escape(NULL, finfo->filename, 0);`
...
`tmp_path = curl_maprintf("%s%s", wildcard->path, enc);`
...
`ftp->pathalloc = ftp->path = tmp_path;`

curl_easy_escape() percent-encodes everything except the RFC 3986 unreserved character set (A-Za-z0-9-._~), critically, . is NOT encoded. A filename of ../etc/passwd therefore escapes to ..%2Fetc%2Fpasswd (dots preserved literally, only the / gets encoded).

Immediately afterward, ftp_parse_url_path() (lib/ftp.c:207-227) is called on this same path, and its very first step is:

`result = Curl_urldecode(ftp->path, 0, &ftpc->rawpath, &pathLen, REJECT_CTRL);`

This URL-decodes the path, reconstructing the literal ../etc/passwd sequence. REJECT_CTRL only rejects control characters (confirmed by reading Curl_urldecode's REJECT_CTRL handling), there is no ..-component filtering or path-normalization check anywhere in this flow before the resulting path is used to drive the subsequent CWD/RETR sequence.

PoC

  1. Attacker controls or MITMs an FTP server.
  2. The client application uses wildcard matching: curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L) against a URL like ftp://server/pub/*.txt
  3. The attacker's FTP LIST response includes a filename such as "../../etc/passwd" (or an absolute-looking component).
  4. curl_easy_escape() encodes it to "..%2F..%2Fetc%2Fpasswd" (dots preserved, slashes encoded).
  5. It is concatenated onto the current wildcard path.
  6. ftp_parse_url_path() -> Curl_urldecode() decodes it straight back to "../../etc/passwd" (or similar), with only control-character filtering.
  7. The resulting path drives the client's CWD/RETR sequence, traversing outside the directory the calling application intended to browse.

Suggested patch:

After URL-decoding in ftp_parse_url_path(), validate that the resulting
path does not contain ".." components that traverse outside the intended
directory. Alternatively, validate finfo->filename in the
CURLWC_DOWNLOADING state before it is ever escaped reject filenames
containing "/", "..", or an absolute-path leading "/".

Impact

Summary:

An application using CURLOPT_WILDCARDMATCH against an untrusted or compromised FTP server can be made to download files from arbitrary paths on that server, outside the directory the calling code intended, an information-disclosure / path-confinement bypass. Requires the calling application to have opted into wildcard matching; does not affect the default (non-wildcard) FTP/SFTP/HTTP transfer paths.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original