Skip to content

Strip auth headers on cross-origin redirects#36

Merged
haarg merged 5 commits into
Perl-Toolchain-Gang:masterfrom
oalders:redirect-headers
May 20, 2026
Merged

Strip auth headers on cross-origin redirects#36
haarg merged 5 commits into
Perl-Toolchain-Gang:masterfrom
oalders:redirect-headers

Conversation

@oalders
Copy link
Copy Markdown
Contributor

@oalders oalders commented May 14, 2026

  • refuse https to http redirects by default
  • strip auth headers on cross-origin redirects
  • Fix protocol-relative Location handling so it can't be used to bypass credential strip
  • demonstrate that https upgrade now strips credentials

@oalders
Copy link
Copy Markdown
Contributor Author

oalders commented May 14, 2026

This changes defaults, so I think it merits a very close look and possibly some arguments.

Comment thread lib/HTTP/Tiny.pm
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allow_credential_redirects is a footgun.

Some people will enable it because it seems to make their lives easier (or maybe they were frobnicating and left it enabled), and it will come back to hurt them badly.

Instead, what you want is to look at the CORS headers from the server, notably https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Credentials will say whether cookies and authentication headers can be shared.

I'd leave out the allow_credential_redirects and take the time to implement CORS handling in a later change.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CORS header doesn't really apply to this.

With an Access-Control-Allow-Credendials: true, the credentials (basic auth, cookies) for the new host should be included in the cross origin request. This requires having a cookie jar, and tracking per-host authorization. LWP does this, but HTTP::Tiny does not.

The behavior with this option just carries the manually set authorization headers through to the redirected requests. No attempt at per-host handling is done. This matches how curl's CURLOPT_UNRESTRICTED_AUTH option works.

Copy link
Copy Markdown
Member

@haarg haarg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests should also cover redirects from requests providing basic auth via the URL (https://user:pass@host/) rather than a manually set Authorization header, with and without the allow_credentialed_redirects option.

Comment thread lib/HTTP/Tiny.pm
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CORS header doesn't really apply to this.

With an Access-Control-Allow-Credendials: true, the credentials (basic auth, cookies) for the new host should be included in the cross origin request. This requires having a cookie jar, and tracking per-host authorization. LWP does this, but HTTP::Tiny does not.

The behavior with this option just carries the manually set authorization headers through to the redirected requests. No attempt at per-host handling is done. This matches how curl's CURLOPT_UNRESTRICTED_AUTH option works.

…he URL

 rather than a manually set Authorization header, with and without the
 allow_credentialed_redirects option.
@oalders
Copy link
Copy Markdown
Contributor Author

oalders commented May 15, 2026

I've added new tests.

@oalders
Copy link
Copy Markdown
Contributor Author

oalders commented May 19, 2026

Anything left to do here?

@haarg
Copy link
Copy Markdown
Member

haarg commented May 20, 2026

Thinking about this a bit more, should we be including any of the original headers when performing a redirect?

@oalders
Copy link
Copy Markdown
Contributor Author

oalders commented May 20, 2026

https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4-6.3.1

Consider removing header fields that were not automatically generated by the implementation (i.e., those present in the request because they were added by the calling context) where there are security implications; this includes but is not limited to Authorization and Cookie.

See also https://curl.se/docs/CVE-2018-1000007.html

curl added the --location-trusted escape hatch/footgun. We could also match that terminology if we found it to be helpful.

We could also consider allowing the caller to specify a list of additional headers to strip.

@haarg
Copy link
Copy Markdown
Member

haarg commented May 20, 2026

I don't think we need to make the problem more complex. If someone needs non-standard behavior for redirects, they can disable the built in redirect handling and do it themselves. HTTP::Tiny does not need to handle every case built in.

@haarg haarg merged commit 95dfccb into Perl-Toolchain-Gang:master May 20, 2026
19 checks passed
@oalders oalders deleted the redirect-headers branch May 20, 2026 16:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants