From 27968574f1a2985e7d73df90edb12877c1302d35 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 16 Jul 2026 12:59:43 -0400 Subject: [PATCH] ext/standard: check the from address for control characters before PASS GH-17976 sanitized from and user_agent where the HTTP wrapper emits headers, and left the FTP wrapper for a follow-up. php_ftp_fopen_connect() sends FG(from_address) as the anonymous password without a check, so an ini_set() value carrying CRLF puts extra commands on the control channel. Apply PHP_FTP_CNTRL_CHK, as the branch that sends a URL-supplied password already does. Closes GH-22770 --- ext/standard/ftp_fopen_wrapper.c | 2 + .../tests/streams/ftp_from_address_cntrl.phpt | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 ext/standard/tests/streams/ftp_from_address_cntrl.phpt diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index dfe905a8c220..0214b8119e06 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -269,6 +269,8 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* if the user has configured who they are, send that as the password */ if (FG(from_address)) { + PHP_FTP_CNTRL_CHK(ZSTR_VAL(FG(from_address)), ZSTR_LEN(FG(from_address)), "Invalid password %s") + php_stream_printf(stream, "PASS %s\r\n", ZSTR_VAL(FG(from_address))); } else { php_stream_write_string(stream, "PASS anonymous\r\n"); diff --git a/ext/standard/tests/streams/ftp_from_address_cntrl.phpt b/ext/standard/tests/streams/ftp_from_address_cntrl.phpt new file mode 100644 index 000000000000..dd64e0c1e34d --- /dev/null +++ b/ext/standard/tests/streams/ftp_from_address_cntrl.phpt @@ -0,0 +1,54 @@ +--TEST-- +ftp:// wrapper must reject control characters in the from address sent as the anonymous password +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false)