Summary
A formula/cask download header: carrying a HOMEBREW_* secret (the deferred-secret feature, used for private taps/registries) is re-sent to a server-supplied cross-host redirect target, leaking the secret to an attacker host. The cross-host header-drop is decided only from the HEAD preflight, while both the preflight and the GET follow redirects with --location.
Details
Library/Homebrew/download_strategy/curl_download_strategy.rb:80-82 drops headers cross-host only when the HEAD-preflight result (is_redirection) shows a host change.
:289 (_curl_args) re-adds --header with the expanded HOMEBREW_ secret for Homebrew-controlled curl strategies; Library/Homebrew/utils/curl.rb follows redirects with --location on both the --head preflight and the real GET.
- Two leak windows result:
- A (GET-time TOCTOU): the HEAD preflight returns a same-host 200, so the drop never runs; the subsequent GET then follows a cross-host 301 with the secret header attached.
- B (HEAD-preflight
--location): the preflight itself follows a cross-host redirect and re-sends the header.
- The recent fix
cf46c16827 ("Expand deferred env in curl URLs", PR #22886, Fixes #22879, merged 2026-06-26) was checked against this report and does not close it. That change gates secret expansion behind a HOMEBREW_CONTROLLED_STRATEGIES allowlist to stop untrusted/custom-formula code from expanding secrets — a different vector. The default CurlDownloadStrategy / CurlGitHubPackagesDownloadStrategy are in that allowlist, so on the normal private-download path the secret is still expanded into --header; the drop logic and utils/curl.rb are unchanged, so both windows remain. (The same commit now also expands deferred env into curl URLs/argv for controlled strategies, which widens local process-listing exposure of the secret — not a new cross-host leak, but the reporter notes it for completeness.)
The reporter recommends dropping custom non-Authorization headers (and the deferred secret) on any cross-host redirect of the actual transfer and of the preflight, rather than from a HEAD-preflight-time decision. Final severity and remediation are the PSRT's to decide.
PoC
Loopback, synthetic. Two loopback listeners: an "origin" that returns a same-host 200 on the HEAD preflight then a cross-host 301 on GET, and an "attacker" listener that logs request headers. A formula sets header "PRIVATE-TOKEN: #{ENV["HOMEBREW_FOO"]}" (synthetic token) and a url to the origin; brew fetch. Observed: the synthetic PRIVATE-TOKEN value lands in the attacker listener's captured headers, via both windows. Negative control: a same-host redirect leaks nothing. (Full recorded stdout available on request / in the private review bundle.)
Impact
Exfiltration of a private token/credential carried in a download header to an attacker-controlled host. Who is impacted: a user who installs a formula/cask that uses a HOMEBREW_-secret header, when an attacker can influence/MITM a cross-host redirect on the download URL. CWE-200 (Exposure of Sensitive Information), CWE-601 (URL Redirection to Untrusted Site).
AI/LLM use disclosure
This finding was researched and validated with AI/LLM assistance; the reporter verified its correctness against the source and the recorded run, and takes full responsibility for it.
- How: an AI agent system (Anthropic Claude, via Claude Code) performed native source-code review to surface the candidate, then orchestrated a live proof-of-concept on a disposable, isolated Linux VM (loopback servers, synthetic inputs only). AI output was treated as a fallible first draft; the sink, reachability, and PoC result were human-verified before reporting.
- When: 2026-06-26 – 2026-06-27, against
master HEAD c0ed315adb.
- Where: in the research (discovery + PoC validation) and in drafting this write-up.
- Prompts: the operative instruction was — "find every 0-day from the latest HEAD; every finding must have a PoC/wire-proof with recorded reachability stdout; conform with the security model and vuln-filing conventions; use disposable VMs within policy to fan out." For this finding: stand up two loopback listeners (origin returns same-host 200 on HEAD then cross-host 301 on GET; attacker logs headers), install a formula with a
HOMEBREW_-secret header, brew fetch, and assert whether the synthetic token reaches the attacker host. Full prompt/agent logs are available to the PSRT on request.
Summary
A formula/cask download
header:carrying aHOMEBREW_*secret (the deferred-secret feature, used for private taps/registries) is re-sent to a server-supplied cross-host redirect target, leaking the secret to an attacker host. The cross-host header-drop is decided only from the HEAD preflight, while both the preflight and the GET follow redirects with--location.Details
Library/Homebrew/download_strategy/curl_download_strategy.rb:80-82drops headers cross-host only when the HEAD-preflight result (is_redirection) shows a host change.:289(_curl_args) re-adds--headerwith the expandedHOMEBREW_secret for Homebrew-controlled curl strategies;Library/Homebrew/utils/curl.rbfollows redirects with--locationon both the--headpreflight and the real GET.--location): the preflight itself follows a cross-host redirect and re-sends the header.cf46c16827("Expand deferred env in curl URLs", PR #22886, Fixes #22879, merged 2026-06-26) was checked against this report and does not close it. That change gates secret expansion behind aHOMEBREW_CONTROLLED_STRATEGIESallowlist to stop untrusted/custom-formula code from expanding secrets — a different vector. The defaultCurlDownloadStrategy/CurlGitHubPackagesDownloadStrategyare in that allowlist, so on the normal private-download path the secret is still expanded into--header; the drop logic andutils/curl.rbare unchanged, so both windows remain. (The same commit now also expands deferred env into curl URLs/argv for controlled strategies, which widens local process-listing exposure of the secret — not a new cross-host leak, but the reporter notes it for completeness.)The reporter recommends dropping custom non-
Authorizationheaders (and the deferred secret) on any cross-host redirect of the actual transfer and of the preflight, rather than from a HEAD-preflight-time decision. Final severity and remediation are the PSRT's to decide.PoC
Loopback, synthetic. Two loopback listeners: an "origin" that returns a same-host 200 on the HEAD preflight then a cross-host 301 on GET, and an "attacker" listener that logs request headers. A formula sets
header "PRIVATE-TOKEN: #{ENV["HOMEBREW_FOO"]}"(synthetic token) and a url to the origin;brew fetch. Observed: the syntheticPRIVATE-TOKENvalue lands in the attacker listener's captured headers, via both windows. Negative control: a same-host redirect leaks nothing. (Full recorded stdout available on request / in the private review bundle.)Impact
Exfiltration of a private token/credential carried in a download header to an attacker-controlled host. Who is impacted: a user who installs a formula/cask that uses a
HOMEBREW_-secret header, when an attacker can influence/MITM a cross-host redirect on the download URL. CWE-200 (Exposure of Sensitive Information), CWE-601 (URL Redirection to Untrusted Site).AI/LLM use disclosure
This finding was researched and validated with AI/LLM assistance; the reporter verified its correctness against the source and the recorded run, and takes full responsibility for it.
masterHEADc0ed315adb.HOMEBREW_-secret header,brew fetch, and assert whether the synthetic token reaches the attacker host. Full prompt/agent logs are available to the PSRT on request.