From 84984ef3930ddd4afcf5eb83b40d3cee200739c3 Mon Sep 17 00:00:00 2001 From: Olaf Alders Date: Thu, 14 May 2026 00:13:01 +0000 Subject: [PATCH 1/5] refuse https to http redirects by default Allow opt in via allow_downgrade --- Changes | 4 ++++ corpus/redirect-11.txt | 21 +++++++++++++++++++++ corpus/redirect-12.txt | 36 ++++++++++++++++++++++++++++++++++++ corpus/redirect-13.txt | 35 +++++++++++++++++++++++++++++++++++ corpus/redirect-14.txt | 35 +++++++++++++++++++++++++++++++++++ lib/HTTP/Tiny.pm | 14 ++++++++++++-- t/001_api.t | 2 +- 7 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 corpus/redirect-11.txt create mode 100644 corpus/redirect-12.txt create mode 100644 corpus/redirect-13.txt create mode 100644 corpus/redirect-14.txt diff --git a/Changes b/Changes index bcbd714..5e478d1 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,10 @@ Release notes for HTTP-Tiny {{$NEXT}} + [CHANGED] + + - Redirects are no longer automatically followed when going from https to http. + Use allow_downgrade to revert to the original behaviour. 0.093 2026-05-11 17:18:12+02:00 Europe/Brussels (TRIAL RELEASE) diff --git a/corpus/redirect-11.txt b/corpus/redirect-11.txt new file mode 100644 index 0000000..6ecdf4d --- /dev/null +++ b/corpus/redirect-11.txt @@ -0,0 +1,21 @@ +url + https://victim.example/secret +expected + refused-redirect-body +expected_url + https://victim.example/secret +---------- +GET /secret HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 21 +Location: http://victim.example/secret + +refused-redirect-body + diff --git a/corpus/redirect-12.txt b/corpus/redirect-12.txt new file mode 100644 index 0000000..8509b24 --- /dev/null +++ b/corpus/redirect-12.txt @@ -0,0 +1,36 @@ +url + https://victim.example/secret +expected + success +expected_url + http://victim.example/secret +new_args + allow_downgrade: 1 +---------- +GET /secret HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://victim.example/secret + +redirect + +---------- +GET /secret HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 7 + +success diff --git a/corpus/redirect-13.txt b/corpus/redirect-13.txt new file mode 100644 index 0000000..6d22dc9 --- /dev/null +++ b/corpus/redirect-13.txt @@ -0,0 +1,35 @@ +url + https://example.com/index.html +expected + abcdefghijklmnopqrstuvwxyz1234567890abcdef +expected_url + https://example.com/index2.html +---------- +GET /index.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/html +Content-Length: 53 +Location: https://example.com/index2.html + +redirect + +---------- +GET /index2.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 42 + +abcdefghijklmnopqrstuvwxyz1234567890abcdef + diff --git a/corpus/redirect-14.txt b/corpus/redirect-14.txt new file mode 100644 index 0000000..31e81f3 --- /dev/null +++ b/corpus/redirect-14.txt @@ -0,0 +1,35 @@ +url + http://example.com/index.html +expected + abcdefghijklmnopqrstuvwxyz1234567890abcdef +expected_url + https://example.com/index2.html +---------- +GET /index.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/html +Content-Length: 53 +Location: https://example.com/index2.html + +redirect + +---------- +GET /index2.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 42 + +abcdefghijklmnopqrstuvwxyz1234567890abcdef + diff --git a/lib/HTTP/Tiny.pm b/lib/HTTP/Tiny.pm index ff6241e..42a0328 100644 --- a/lib/HTTP/Tiny.pm +++ b/lib/HTTP/Tiny.pm @@ -18,6 +18,10 @@ This constructor returns a new HTTP::Tiny object. Valid attributes include: * C — A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C — ends in a space character, the default user-agent string is appended. +* C — If a 3xx redirect changes the scheme from C to + plain C, HTTP::Tiny will by default refuse to follow it, returning the + 3xx response. Set this to a true value to revert to the legacy behavior of + redirecting C to C. Default is C. * C — An instance of L — or equivalent class that supports the C and C methods * C — A hashref of default headers to apply to requests @@ -81,8 +85,8 @@ attributes. my @attributes; BEGIN { @attributes = qw( - cookie_jar default_headers http_proxy https_proxy keep_alive - local_address max_redirect max_size proxy no_proxy + allow_downgrade cookie_jar default_headers http_proxy https_proxy + keep_alive local_address max_redirect max_size proxy no_proxy SSL_options verify_SSL ); my %persist_ok = map {; $_ => 1 } qw( @@ -972,6 +976,11 @@ sub _maybe_redirect { my $location = ($headers->{location} =~ /^\//) ? "$request->{scheme}://$request->{host_port}$headers->{location}" : $headers->{location} ; + my ($to_scheme) = $self->_split_url($location); + if (!$self->{allow_downgrade} && $request->{scheme} eq 'https' && $to_scheme eq 'http' ) { + return; + } + return (($status eq '303' ? 'GET' : $method), $location); } return; @@ -1767,6 +1776,7 @@ sub _ssl_args { =for Pod::Coverage SSL_options agent +allow_downgrade cookie_jar default_headers http_proxy diff --git a/t/001_api.t b/t/001_api.t index 48cc2f8..7e1fa57 100755 --- a/t/001_api.t +++ b/t/001_api.t @@ -7,7 +7,7 @@ use Test::More tests => 2; use HTTP::Tiny; my @accessors = qw( - agent default_headers http_proxy https_proxy keep_alive local_address + agent allow_downgrade default_headers http_proxy https_proxy keep_alive local_address max_redirect max_size proxy no_proxy timeout SSL_options verify_SSL cookie_jar ); my @methods = qw( From e7a03aedf2395158f2b0d3bad2df943349227bb3 Mon Sep 17 00:00:00 2001 From: Olaf Alders Date: Thu, 14 May 2026 17:50:22 +0000 Subject: [PATCH 2/5] strip auth headers on cross-origin redirects --- Changes | 6 ++++- corpus/redirect-15.txt | 57 ++++++++++++++++++++++++++++++++++++++++++ corpus/redirect-16.txt | 47 ++++++++++++++++++++++++++++++++++ corpus/redirect-17.txt | 39 +++++++++++++++++++++++++++++ corpus/redirect-18.txt | 38 ++++++++++++++++++++++++++++ corpus/redirect-19.txt | 40 +++++++++++++++++++++++++++++ corpus/redirect-20.txt | 41 ++++++++++++++++++++++++++++++ lib/HTTP/Tiny.pm | 32 +++++++++++++++++++----- t/001_api.t | 5 ++-- 9 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 corpus/redirect-15.txt create mode 100644 corpus/redirect-16.txt create mode 100644 corpus/redirect-17.txt create mode 100644 corpus/redirect-18.txt create mode 100644 corpus/redirect-19.txt create mode 100644 corpus/redirect-20.txt diff --git a/Changes b/Changes index 5e478d1..82676eb 100644 --- a/Changes +++ b/Changes @@ -1,7 +1,11 @@ Release notes for HTTP-Tiny {{$NEXT}} - [CHANGED] + [!!! SECURITY !!!] + + - Caller-supplied C, C, and C + headers are now stripped on cross-origin redirects by default. Use + allow_credentialed_redirects to opt out. - Redirects are no longer automatically followed when going from https to http. Use allow_downgrade to revert to the original behaviour. diff --git a/corpus/redirect-15.txt b/corpus/redirect-15.txt new file mode 100644 index 0000000..35eb003 --- /dev/null +++ b/corpus/redirect-15.txt @@ -0,0 +1,57 @@ +url + http://victim.example/secret +expected + pwned +expected_url + http://victim.example/back +headers + Authorization: Bearer SECRET-TOKEN + Cookie: session=SECRET-SESSION + Proxy-Authorization: Basic c2VjcmV0OnNlY3JldA== +---------- +GET /secret HTTP/1.1 +Host: victim.example +Authorization: Bearer SECRET-TOKEN +Cookie: session=SECRET-SESSION +Proxy-Authorization: Basic c2VjcmV0OnNlY3JldA== +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://victim.example/back + +redirect + +---------- +GET /back HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 5 + +pwned + diff --git a/corpus/redirect-16.txt b/corpus/redirect-16.txt new file mode 100644 index 0000000..986a95d --- /dev/null +++ b/corpus/redirect-16.txt @@ -0,0 +1,47 @@ +url + http://victim.example/secret +expected + pwned +expected_url + http://attacker.example/loot +new_args + allow_credentialed_redirects: 1 +headers + Authorization: Bearer SECRET-TOKEN + Cookie: session=SECRET-SESSION + Proxy-Authorization: Basic c2VjcmV0OnNlY3JldA== +---------- +GET /secret HTTP/1.1 +Host: victim.example +Authorization: Bearer SECRET-TOKEN +Cookie: session=SECRET-SESSION +Proxy-Authorization: Basic c2VjcmV0OnNlY3JldA== +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Authorization: Bearer SECRET-TOKEN +Cookie: session=SECRET-SESSION +Proxy-Authorization: Basic c2VjcmV0OnNlY3JldA== +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 5 + +pwned + diff --git a/corpus/redirect-17.txt b/corpus/redirect-17.txt new file mode 100644 index 0000000..141dd6c --- /dev/null +++ b/corpus/redirect-17.txt @@ -0,0 +1,39 @@ +url + http://example.com/a +expected + ok +expected_url + http://example.com/b +headers + Authorization: Bearer SECRET-TOKEN +---------- +GET /a HTTP/1.1 +Host: example.com +Authorization: Bearer SECRET-TOKEN +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://example.com/b + +redirect + +---------- +GET /b HTTP/1.1 +Host: example.com +Authorization: Bearer SECRET-TOKEN +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + diff --git a/corpus/redirect-18.txt b/corpus/redirect-18.txt new file mode 100644 index 0000000..09e8073 --- /dev/null +++ b/corpus/redirect-18.txt @@ -0,0 +1,38 @@ +url + http://example.com:8080/foo +expected + ok +expected_url + http://example.com:8081/bar +headers + Authorization: Bearer SECRET-TOKEN +---------- +GET /foo HTTP/1.1 +Host: example.com:8080 +Authorization: Bearer SECRET-TOKEN +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://example.com:8081/bar + +redirect + +---------- +GET /bar HTTP/1.1 +Host: example.com:8081 +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + diff --git a/corpus/redirect-19.txt b/corpus/redirect-19.txt new file mode 100644 index 0000000..2b52d20 --- /dev/null +++ b/corpus/redirect-19.txt @@ -0,0 +1,40 @@ +url + https://example.com:8443/foo +expected + ok +expected_url + http://example.com:8443/foo +new_args + allow_downgrade: 1 +headers + Authorization: Bearer SECRET-TOKEN +---------- +GET /foo HTTP/1.1 +Host: example.com:8443 +Authorization: Bearer SECRET-TOKEN +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://example.com:8443/foo + +redirect + +---------- +GET /foo HTTP/1.1 +Host: example.com:8443 +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + diff --git a/corpus/redirect-20.txt b/corpus/redirect-20.txt new file mode 100644 index 0000000..9553352 --- /dev/null +++ b/corpus/redirect-20.txt @@ -0,0 +1,41 @@ +url + http://victim.example/submit +method + POST +expected + ok +expected_url + http://attacker.example/loot +headers + Authorization: Bearer SECRET-TOKEN +---------- +POST /submit HTTP/1.1 +Host: victim.example +Authorization: Bearer SECRET-TOKEN +Connection: close +Content-Length: 0 +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 303 See Other +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: http://attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + diff --git a/lib/HTTP/Tiny.pm b/lib/HTTP/Tiny.pm index 42a0328..336d1a2 100644 --- a/lib/HTTP/Tiny.pm +++ b/lib/HTTP/Tiny.pm @@ -18,6 +18,12 @@ This constructor returns a new HTTP::Tiny object. Valid attributes include: * C — A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C — ends in a space character, the default user-agent string is appended. +* C - If a 3xx redirects to a different scheme, + host or port, by default HTTP::Tiny will strip away caller-supplied + C, C and C headers from the + redirected request and from all subsequent requests in the chain. Set this to a + true value to revert to the legacy behavior of forwarding those headers. + Default is C. * C — If a 3xx redirect changes the scheme from C to plain C, HTTP::Tiny will by default refuse to follow it, returning the 3xx response. Set this to a true value to revert to the legacy behavior of @@ -85,9 +91,9 @@ attributes. my @attributes; BEGIN { @attributes = qw( - allow_downgrade cookie_jar default_headers http_proxy https_proxy - keep_alive local_address max_redirect max_size proxy no_proxy - SSL_options verify_SSL + allow_credentialed_redirects allow_downgrade cookie_jar default_headers + http_proxy https_proxy keep_alive local_address max_redirect max_size + proxy no_proxy SSL_options verify_SSL ); my %persist_ok = map {; $_ => 1 } qw( cookie_jar default_headers max_redirect max_size @@ -368,8 +374,7 @@ Don't use C when you really want C. See L for how this applies to redirection. If the URL includes a "user:password" stanza, they will be used for Basic-style -authorization headers. (Authorization headers will not be included in a -redirected request.) For example: +authorization headers. For example: $http->request('GET', 'http://Aladdin:open sesame@example.com/'); @@ -378,6 +383,10 @@ be percent-escaped: $http->request('GET', 'http://john%40example.com:password@example.com/'); +Caller-supplied C, C and C headers +are stripped on cross-origin redirects. See L's +C attribute to opt out. + A hashref of options may be appended to modify the request. Valid options are: @@ -462,6 +471,7 @@ contain 599, and the C field will contain the text of the error. =cut my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/; +my %sensitive_headers = map { $_ => 1 } qw/authorization cookie proxy-authorization/; sub request { my ($self, $method, $url, $args) = @_; @@ -846,6 +856,7 @@ sub _prepare_headers_and_cb { for ($self->{default_headers}, $args->{headers}) { next unless defined; while (my ($k, $v) = each %$_) { + next if $args->{_strip_credentials} && exists $sensitive_headers{lc $k}; $request->{headers}{lc $k} = $v; $request->{header_case}{lc $k} = $k; } @@ -976,10 +987,18 @@ sub _maybe_redirect { my $location = ($headers->{location} =~ /^\//) ? "$request->{scheme}://$request->{host_port}$headers->{location}" : $headers->{location} ; - my ($to_scheme) = $self->_split_url($location); + my ($to_scheme, $to_host, $to_port) = $self->_split_url($location); if (!$self->{allow_downgrade} && $request->{scheme} eq 'https' && $to_scheme eq 'http' ) { return; } + if ( + !$self->{allow_credentialed_redirects} + && ( $request->{scheme} ne $to_scheme + || $request->{host} ne $to_host + || $request->{port} ne $to_port ) + ) { + $args->{_strip_credentials} = 1; + } return (($status eq '303' ? 'GET' : $method), $location); } @@ -1776,6 +1795,7 @@ sub _ssl_args { =for Pod::Coverage SSL_options agent +allow_credentialed_redirects allow_downgrade cookie_jar default_headers diff --git a/t/001_api.t b/t/001_api.t index 7e1fa57..403fff7 100755 --- a/t/001_api.t +++ b/t/001_api.t @@ -7,8 +7,9 @@ use Test::More tests => 2; use HTTP::Tiny; my @accessors = qw( - agent allow_downgrade default_headers http_proxy https_proxy keep_alive local_address - max_redirect max_size proxy no_proxy timeout SSL_options verify_SSL cookie_jar + agent allow_credentialed_redirects allow_downgrade default_headers http_proxy + https_proxy keep_alive local_address max_redirect max_size proxy no_proxy timeout + SSL_options verify_SSL cookie_jar ); my @methods = qw( new get head put post patch delete post_form request mirror www_form_urlencode can_ssl From 8f32ca89e21c3ad0422adc698fa6ad17a193f55f Mon Sep 17 00:00:00 2001 From: Olaf Alders Date: Thu, 14 May 2026 20:18:15 +0000 Subject: [PATCH 3/5] Fix protocol-relative Location handling so it can't be used to bypass credential strip --- corpus/redirect-21.txt | 38 ++++++++++++++++++++++++++++++++++++++ lib/HTTP/Tiny.pm | 6 ++++-- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 corpus/redirect-21.txt diff --git a/corpus/redirect-21.txt b/corpus/redirect-21.txt new file mode 100644 index 0000000..8670368 --- /dev/null +++ b/corpus/redirect-21.txt @@ -0,0 +1,38 @@ +url + https://victim.example/x +expected + pwned +expected_url + https://attacker.example/loot +headers + Authorization: Bearer TRUSTED-TOKEN +---------- +GET /x HTTP/1.1 +Host: victim.example +Authorization: Bearer TRUSTED-TOKEN +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: //attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 5 + +pwned + diff --git a/lib/HTTP/Tiny.pm b/lib/HTTP/Tiny.pm index 336d1a2..3dc828b 100644 --- a/lib/HTTP/Tiny.pm +++ b/lib/HTTP/Tiny.pm @@ -984,9 +984,11 @@ sub _maybe_redirect { and $headers->{location} and @{$args->{_redirects}} < $self->{max_redirect} ) { - my $location = ($headers->{location} =~ /^\//) + my $location = $headers->{location} =~ m{^//} + ? "$request->{scheme}:$headers->{location}" + : $headers->{location} =~ m{^/} ? "$request->{scheme}://$request->{host_port}$headers->{location}" - : $headers->{location} ; + : $headers->{location}; my ($to_scheme, $to_host, $to_port) = $self->_split_url($location); if (!$self->{allow_downgrade} && $request->{scheme} eq 'https' && $to_scheme eq 'http' ) { return; From 0d7b31e7a16281e918e68fad855ddf249209b026 Mon Sep 17 00:00:00 2001 From: Olaf Alders Date: Thu, 14 May 2026 20:37:52 +0000 Subject: [PATCH 4/5] demonstrate that https upgrade now strips credentials as it is a change of origin --- corpus/redirect-22.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 corpus/redirect-22.txt diff --git a/corpus/redirect-22.txt b/corpus/redirect-22.txt new file mode 100644 index 0000000..c5534a6 --- /dev/null +++ b/corpus/redirect-22.txt @@ -0,0 +1,40 @@ +url + http://example.com/login +expected + ok +expected_url + https://example.com/login +headers + Authorization: Bearer SECRET-TOKEN + Cookie: session=SECRET-SESSION +---------- +GET /login HTTP/1.1 +Host: example.com +Authorization: Bearer SECRET-TOKEN +Cookie: session=SECRET-SESSION +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: https://example.com/login + +redirect + +---------- +GET /login HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + From d9aa62b0013abb790b3cf45340320fae475ffdb2 Mon Sep 17 00:00:00 2001 From: Olaf Alders Date: Fri, 15 May 2026 20:48:11 +0000 Subject: [PATCH 5/5] Add tests to cover redirects from requests providing basic auth via the URL rather than a manually set Authorization header, with and without the allow_credentialed_redirects option. --- corpus/redirect-23.txt | 36 ++++++++++++++++++++++++++++++++++++ corpus/redirect-24.txt | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 corpus/redirect-23.txt create mode 100644 corpus/redirect-24.txt diff --git a/corpus/redirect-23.txt b/corpus/redirect-23.txt new file mode 100644 index 0000000..de44874 --- /dev/null +++ b/corpus/redirect-23.txt @@ -0,0 +1,36 @@ +url + https://user:pass@victim.example/secret +expected + ok +expected_url + https://attacker.example/loot +---------- +GET /secret HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION +Authorization: Basic dXNlcjpwYXNz + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: https://attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok + diff --git a/corpus/redirect-24.txt b/corpus/redirect-24.txt new file mode 100644 index 0000000..c203e97 --- /dev/null +++ b/corpus/redirect-24.txt @@ -0,0 +1,38 @@ +url + https://user:pass@victim.example/secret +expected + ok +expected_url + https://attacker.example/loot +new_args + allow_credentialed_redirects: 1 +---------- +GET /secret HTTP/1.1 +Host: victim.example +Connection: close +User-Agent: HTTP-Tiny/VERSION +Authorization: Basic dXNlcjpwYXNz + +---------- +HTTP/1.1 302 Found +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 8 +Location: https://attacker.example/loot + +redirect + +---------- +GET /loot HTTP/1.1 +Host: attacker.example +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 2 + +ok +