diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index c078faaed5c..79ec2903665 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -592,12 +592,20 @@ protected override void ProcessRecord() OutFile = null; } - // Detect insecure redirection - if (!AllowInsecureRedirect && response.RequestMessage.RequestUri.Scheme == "https" && response.Headers.Location?.Scheme == "http") + // Detect insecure redirection. + if (!AllowInsecureRedirect) { - ErrorRecord er = new(new InvalidOperationException(), "InsecureRedirection", ErrorCategory.InvalidOperation, request); - er.ErrorDetails = new ErrorDetails(WebCmdletStrings.InsecureRedirection); - ThrowTerminatingError(er); + // We will skip detection if either of the URIs is relative, because the 'Scheme' property is not supported on a relative URI. + // If we have to skip the check, an error may be thrown later if it's actually an insecure https-to-http redirect. + bool originIsHttps = response.RequestMessage.RequestUri.IsAbsoluteUri && response.RequestMessage.RequestUri.Scheme == "https"; + bool destinationIsHttp = response.Headers.Location is not null && response.Headers.Location.IsAbsoluteUri && response.Headers.Location.Scheme == "http"; + + if (originIsHttps && destinationIsHttp) + { + ErrorRecord er = new(new InvalidOperationException(), "InsecureRedirection", ErrorCategory.InvalidOperation, request); + er.ErrorDetails = new ErrorDetails(WebCmdletStrings.InsecureRedirection); + ThrowTerminatingError(er); + } } if (ShouldCheckHttpStatus && !_isSuccess) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 5f1e6e4bae3..b07afbe3627 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1149,6 +1149,15 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $result = ExecuteWebCommand -command $command $result.Error.FullyQualifiedErrorId | Should -Be "InsecureRedirection,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" } + + It "Validate Invoke-WebRequest Https to Http (No Scheme) redirect without -AllowInsecureRedirect" { + $httpUri = Get-WebListenerUrl -Test 'Get' + $uri = Get-WebListenerUrl -Test 'Redirect' -Https -Query @{destination = $httpUri.Authority} + $command = "Invoke-WebRequest -Uri '$uri' -SkipCertificateCheck" + + $result = ExecuteWebCommand -command $command + $result.Error.FullyQualifiedErrorId | Should -Be "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + } } @@ -3100,6 +3109,15 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.Error.FullyQualifiedErrorId | Should -Be "InsecureRedirection,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" } + It "Validate Invoke-RestMethod Https to Http (No Scheme) redirect without -AllowInsecureRedirect" { + $httpUri = Get-WebListenerUrl -Test 'Get' + $uri = Get-WebListenerUrl -Test 'Redirect' -Https -Query @{destination = $httpUri.Authority} + $command = "Invoke-RestMethod -Uri '$uri' -SkipCertificateCheck" + + $result = ExecuteWebCommand -command $command + $result.Error.FullyQualifiedErrorId | Should -Be "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" + } + #endregion Redirect tests Context "Invoke-RestMethod SkipHeaderVerification Tests" {