From ecaa344a7a17874ff0c6e5717489e8f9033c4d5c Mon Sep 17 00:00:00 2001 From: Alhuda Khan Date: Wed, 1 Jul 2026 15:11:15 +0530 Subject: [PATCH] url: reject control codes in credentials set via CURLOPT Closes #22236 --- lib/url.c | 12 +++++++++++- tests/data/Makefile.am | 2 +- tests/data/test2114 | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/data/test2114 diff --git a/lib/url.c b/lib/url.c index 164aef797a..dd4e33c9d1 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1398,7 +1398,6 @@ static CURLcode hsts_upgrade(struct Curl_easy *data, #define hsts_upgrade(x, y, z, a) CURLE_OK #endif -#ifndef CURL_DISABLE_NETRC static bool str_has_ctrl(const char *input) { if(input) { @@ -1412,6 +1411,7 @@ static bool str_has_ctrl(const char *input) return FALSE; } +#ifndef CURL_DISABLE_NETRC /* * Override the login details from the URL with that in the CURLOPT_USERPWD * option or a .netrc file, if applicable. @@ -1538,6 +1538,16 @@ static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh) CREDS_OPTION, &newcreds); if(result) goto out; + if(newcreds && + !(data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL) && + (str_has_ctrl(Curl_creds_user(newcreds)) || + str_has_ctrl(Curl_creds_passwd(newcreds)))) { + /* if the protocol cannot handle control codes in credentials, make + sure there are none */ + failf(data, "control code detected in credentials"); + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto out; + } } /* Extract credentials from the URL only if there are none OR diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 1df0a8053c..4ef4f55f95 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -254,7 +254,7 @@ test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ test2088 test2089 test2090 test2091 test2092 \ test2100 test2101 test2102 test2103 test2104 test2105 test2106 test2107 \ -test2108 test2109 test2110 test2113 \ +test2108 test2109 test2110 test2113 test2114 \ \ test2200 test2201 test2202 test2203 test2204 test2205 test2206 test2207 \ test2208 \ diff --git a/tests/data/test2114 b/tests/data/test2114 new file mode 100644 index 0000000000..fe8bc1cf98 --- /dev/null +++ b/tests/data/test2114 @@ -0,0 +1,43 @@ + + + + +FTP + + + +# Server-side + + + +# Client-side + + +ftp + + +FTP username with embedded CRLF is rejected + +# read the credentials from a config file so the raw CR LF reaches curl intact +# regardless of how the platform passes command line arguments + +user = "anonymous\r\nSTOR /%TESTNUMBER" + + +ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -K %LOGDIR/test%TESTNUMBER.config + + + +# Verify data after the test has been "shot" + +# 43 - CURLE_BAD_FUNCTION_ARGUMENT + +43 + +# the credentials are rejected before connecting so the injected STOR command +# must never reach the server + + + + +