[php-src] Issue #24113: [FTP stream wrapper] Validate the PASV-advertised data-channel host

From: Date: Sun, 04 Oct 2026 11:54:27 +0000
Subject: [php-src] Issue #24113: [FTP stream wrapper] Validate the PASV-advertised data-channel host
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-252896@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24113 Author: bupt-Yy-young ### Description In the php-src master snapshot 63b0af4a5c400d93510dca7aa998769609fdc26c (2026-10-04), the FTP stream wrapper uses the host returned in an FTP server's 227 PASV response as the data-channel destination. php_fopen_do_pasv() parses the 227 host into hoststart (ext/standard/ftp_fopen_wrapper.c:341-361), and the open path then connects to tcp://%s:%d using that value (:551-557). I could not find a comparison with the control connection's peer address or a stream-context option to constrain the PASV host. The only effective port rejection in this path is port 0. For an application that fetches attacker-influenced ftp://` URLs, an attacker-operated FTP server can return a PASV tuple for a loopback or private-network address. PHP then attempts the data-channel connection to that address while the attacker controls the FTP control channel. This can provide server-side reachability/port probing of targets reachable from the PHP host; data returned by a target may also be exposed through the caller's read flow when that service sends an unsolicited banner. Any stronger read/write impact depends on how the application consumes the stream. This is a conditional issue: it requires an application to use the FTP wrapper with an attacker-influenced URL and a PHP host that can route to the target. allow_url_fopen is only a scheme gate, not a destination policy. ### Expected behavior Could the stream wrapper bind the data connection to the control connection's peer address by default, or expose a documented opt-in equivalent to the FTP_USEPASVADDRESS setting available to the separate FTP extension API? ### Reproduction outline Run a controlled FTP server and a listener on a local/private address. Have the FTP server return a 227 reply whose tuple names the listener, then request a file through PHP's FTP stream wrapper. The expected observation is whether PHP connects to the PASV-advertised listener rather than to the FTP control peer. I have traced this statically in the referenced source; I have not run this outline against a compiled build. ### Related work This is distinct from [PR #22203](https://github.com/php/php-src/pull/22203), which addresses the bounded-copy/OOB-read issue in the same PASV parser, and from [PR #1668](https://github.com/php/php-src/pull/1668), which added a PASV-address option to the separate FTP extension API.

« previous php.bugs (#252896) next »