mechanize leaked credentials to the redirect target when an HTTP redirect crossed to another host. Credentials set through Mechanize#request_headers= leaked even when they were Authorization.
Two defects, both in lib/mechanize/http/agent.rb.
1. Mechanize#request_headers= bypassed the redirect strip entirely. #request_add_headers copied @request_headers onto every request unconditionally, with no host check, including the request issued after a redirect. The strip in #response_redirect mutated only the per-request headers hash and never touched agent state. Because request_headers= is the documented way to set a default credential for every request, the header the code explicitly protected — Authorization — was the one most likely to leak.
2. The strip list omitted Proxy-Authorization and Cookie2. Only CREDENTIAL_HEADERS = ['Authorization'] and COOKIE_HEADERS = ['Cookie'] were removed from the per-request headers hash on a cross-host redirect.
Cookies held in Mechanize#cookie_jar and credentials held in Mechanize::HTTP::AuthStore are not affected. Both are looked up per-URI, so they never follow a redirect to a foreign host. The exposure was limited to headers the caller set by hand.
agent = Mechanize.new
agent.request_headers = { 'Authorization' => 'Bearer secret' }
agent.get('https://example.test/redirects-to-attacker')
# the request to the attacker's host carries "Authorization: Bearer secret"
An attacker who controls a redirect target — through an open redirect on the site being fetched, an attacker-supplied fetch URL, DNS rebinding, or MITM — captures bearer tokens and session cookies from any mechanize agent that sets credentials through request_headers= or the per-request headers argument. Disclosure only; no integrity or availability impact.
Fixed in mechanize v2.14.1.
headers argument and Mechanize#request_headers=.CREDENTIAL_HEADERS gains Proxy-Authorization; COOKIE_HEADERS gains Cookie2.Proxy-Authorization is withheld here although curl does not withhold it, because Net::HTTP tunnels https: requests with CONNECT, so a caller-supplied Proxy-Authorization travels inside the tunnel to the origin server rather than to the proxy.
Headers set through Mechanize#request_headers= no longer reach a redirect target on another origin when they are credentials. Callers that relied on the previous behavior will see those headers withheld.
Only the headers in CREDENTIAL_HEADERS and COOKIE_HEADERS are withheld. A caller-supplied header that carries a credential under some other name — X-API-Key, X-Vault-Token, or any bespoke token header — still follows a redirect to another origin, matching the behavior of curl's CURLOPT_HTTPHEADER. If you set such a header, do not enable redirect following for requests that carry it, or scope it to a single request whose destination you control.
Set Mechanize#redirect_ok = false and handle redirects explicitly, or avoid request_headers= for credentials and pass them per-request only to hosts you intend to authenticate to.
Reported by @SnailSploit.
{
"cwe_ids": [
"CWE-200",
"CWE-522"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T22:09:00Z",
"nvd_published_at": null,
"severity": "MODERATE"
}