diff --git a/src/libraries/System.Net.Requests/src/Resources/Strings.resx b/src/libraries/System.Net.Requests/src/Resources/Strings.resx
index f8ac54eb739cdd..05b94042590c8c 100644
--- a/src/libraries/System.Net.Requests/src/Resources/Strings.resx
+++ b/src/libraries/System.Net.Requests/src/Resources/Strings.resx
@@ -195,6 +195,9 @@
The underlying connection was closed: An unexpected error occurred on a receive
+
+ CRLF character pair is not allowed in FtpWebRequest inputs.
+
The remote name could not be resolved
diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
index 35eefb9c38cbba..ffba72c9315d28 100644
--- a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
+++ b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
@@ -1118,6 +1118,11 @@ private string GetPortCommandLine()
///
private static string FormatFtpCommand(string command, string? parameter)
{
+ if (parameter is not null && parameter.Contains("\r\n", StringComparison.Ordinal))
+ {
+ throw new FormatException(SR.net_ftp_no_newlines);
+ }
+
return string.IsNullOrEmpty(parameter) ?
command + "\r\n" :
command + " " + parameter + "\r\n";
diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
index 5a6009240fd921..b27873e9edb233 100644
--- a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
+++ b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
@@ -486,6 +486,9 @@ internal FtpWebRequest(Uri uri)
if ((object)uri.Scheme != (object)Uri.UriSchemeFtp)
throw new ArgumentOutOfRangeException(nameof(uri));
+ if (uri.OriginalString.Contains("\r\n", StringComparison.Ordinal))
+ throw new FormatException(SR.net_ftp_no_newlines);
+
_timerCallback = new TimerThread.Callback(TimerCallback);
_syncObject = new object();
diff --git a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
index d1f5e58b3492b5..c2b7ad12524003 100644
--- a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
+++ b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
@@ -203,6 +203,27 @@ public void Ftp_RenameFileSubDir_Success(FtpExecutionMode mode)
Assert.False(DirExists(mode, dir));
}
+ [Fact]
+ public void Ftp_Ignore_NewLine_Constructor_Throws_FormatException()
+ {
+ string uri = absoluteUri + Guid.NewGuid().ToString();
+
+ Assert.Throws(() => WebRequest.Create($"{uri}\r\n{WebRequestMethods.Ftp.AppendFile} {Guid.NewGuid().ToString()}"));
+ }
+
+ [ConditionalFact(nameof(LocalServerAvailable))]
+ public void Ftp_Ignore_NewLine_GetRequestStream_And_GetResponse_Throws_FormatException_As_InnerException()
+ {
+ FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(absoluteUri + Guid.NewGuid().ToString());
+ ftpWebRequest.Method = "APPE";
+ ftpWebRequest.Credentials = new NetworkCredential("test\r\ntest2", "test\r\ntest2");
+ var requestException = Assert.Throws(() => ftpWebRequest.GetRequestStream());
+ Assert.True(requestException.InnerException is FormatException);
+
+ var responseException = Assert.Throws(() => ftpWebRequest.GetResponse());
+ Assert.True(responseException.InnerException is FormatException);
+ }
+
private static async Task DoAsync(FtpWebRequest request, MemoryStream requestBody)
{
if (requestBody != null)