Skip to content

keep fetcher credentials on the first host across redirects - #3469

Merged
tballison merged 1 commit into
apache:mainfrom
mrdevel2002-ui:redirect-credentials-first-host
Nov 2, 2026
Merged

tballison merged 1 commit into
apache:mainfrom
mrdevel2002-ui:redirect-credentials-first-host

Conversation

@mrdevel2002-ui

Copy link
Copy Markdown
Contributor

HttpClientFactory builds the client behind HttpFetcher, AtlassianJwtFetcher and the ES, OpenSearch and Solr plugins. With maxRedirects above 0, HttpClient's RedirectExec copies the original request's headers onto every redirect, and the factory registers configured credentials under AuthScope.ANY. A redirect from a fetched server to another host therefore hands that host the fetcher's Authorization JWT and any Cookie header outright, and the host can collect the configured basic or NTLM password by answering 401 with WWW-Authenticate: Basic. The HTTP fetcher's security notes accept that a redirect can reach any host as an SSRF matter, but they don't say the operator's secrets go along, and the redirect target is chosen by the remote server, not by the trusted caller who chose the fetch key. An open redirect on an otherwise trusted host is enough. curl fixed the same problem as CVE-2018-1000007.

The fix sits in the factory so every client it builds gets it. CredentialsHostGuard records the first hop's target, removes Authorization and Cookie from any later hop on another host, port or scheme, and leaves a challenge from such a host unanswered. It is a request interceptor because RedirectExec refills a redirect that has no headers from the original request, so removing the last header in a redirect strategy would put the JWT straight back. Two trade-offs are worth a look. An http to https upgrade now drops credentials, as it does in curl, so those fetch keys need the https URL. Secrets in custom httpRequestHeaders still follow redirects, because the client can't tell which headers are secret. Both are in the security notes in http.adoc. Same-host redirects behave as before.

HttpFetcherRedirectCredentialsTest runs the real fetcher against two loopback servers on different ports. On main the second server gets the Bearer token on both a direct and a two-hop redirect, and its 401 is answered with the password, so three of the five tests fail. With the patch all five pass; the two same-host tests pass either way. A throwaway test against AtlassianJwtFetcher gave the same result: the first host saw JWT ..., the second nothing. ./mvnw clean apache-rat:check install -Pci of tika-httpclient-commons, tika-pipes-http, tika-pipes-atlassian-jwt, tika-pipes-es, tika-pipes-opensearch and tika-pipes-solr (tests, checkstyle, spotless, forbidden-apis) is green on JDK 21, and the first three modules are also green on JDK 25.

  • open issue on the Tika issue tracker: not filed yet, happy to open one or have it linked
  • issue ID in the PR title and commit message: pending the issue above
  • commits are squashed into a single one
  • Tika builds and unit tests pass with ./mvnw clean install (affected modules)
  • generative AI tool used: Generated-by: Claude Code (Claude Opus 5.5), disclosed here rather than as a commit trailer
  • no conflicts with the recent main branch
  • new downstream module added to tika-bom/pom.xml: not applicable

HttpClient copies the original request's headers onto every redirect
and AuthScope.ANY answers a challenge from any host, so a redirect
handed a fetcher's JWT or basic password to whichever host it named.
Drop Authorization and Cookie once a request has left its first host
and leave a challenge from another host unanswered.
@tballison
tballison merged commit 2102425 into apache:main Nov 2, 2026
4 checks passed
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.

2 participants