Summary
SubversionDownloadStrategy reads a Subversion repository's svn:externals property — a value controlled by the server, not the formula author — and feeds the resulting external URL into svn checkout in option position with no -- end-of-options guard. A svn:externals URL beginning with a dash is therefore parsed by svn as an option. This is the genuinely untrusted-input instance of the download-strategy argument-injection class: a benign formula pointing at a malicious or compromised svn repository is sufficient — no malicious formula content is required. (Reachable when the formula uses svn's multi-revision spec, revisions:, which is what triggers the externals walk in clone_repo; the default/single-revision: svn path does not iterate externals.)
Details
Sink chain in Library/Homebrew/download_strategy/subversion_download_strategy.rb:
:60 svn propget svn:externals <@url> reads the server-controlled externals property.
:62 name, url = line.split(/\s+/) parses each external (the external URL is server-supplied).
:116 fetch_repo(..., external_url, ...) →
:91 command! "svn", args: ["checkout", url, target, *args] — url is the first positional after checkout, with no -- before it.
A dash-leading svn:externals URL (for example --config-dir=<dir>) is parsed by svn as an option. The same :91 sink also takes the formula-author @url; that variant is formula-author-controlled and is reported separately as hardening parity. The svn:externals vector here is the server-supplied, advisory-grade one.
The reporter recommends passing -- before the URL/target in the svn checkout invocation (:91) and rejecting dash-leading svn:externals URLs parsed at :62. Final severity and remediation are the PSRT's to decide.
PoC
Loopback/synthetic. Driving the real HEAD strategy, a server-supplied svn:externals value of --config-dir=<dir> reaches svn checkout in option position and svn acts on it (the named config directory is created/populated) — captured via the real argv plus the on-disk side effect. Negative controls: a benign (non-dash) externals URL is positional with no effect; a ---guarded checkout makes the token positional (rejected as a non-URL). (Full recorded stdout available on request / in the private review bundle.)
Impact
A malicious or compromised Subversion server (or a MITM of a plain svn:///http:// repo) injects svn client options during a Homebrew download via the svn:externals property — without any malicious formula. Who is impacted: a user installing a formula that uses svn's multi-revision spec (revisions:) against an svn source whose svn:externals are attacker-influenced. Bounded to what an injected svn option can do (for example config-dir redirection / behaviour change); no direct command execution was reached. CWE-88 (Argument Injection).
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; live PoC recorded at
bc237f676c, sink re-verified unchanged (empty git diff) at 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: serve a loopback svn repo whose
svn:externals URL is a dash-leading svn option, brew fetch, and assert the option reaches svn checkout in option position via the real argv plus its on-disk side effect. Full prompt/agent logs are available to the PSRT on request.
Summary
SubversionDownloadStrategyreads a Subversion repository'ssvn:externalsproperty — a value controlled by the server, not the formula author — and feeds the resulting external URL intosvn checkoutin option position with no--end-of-options guard. Asvn:externalsURL beginning with a dash is therefore parsed bysvnas an option. This is the genuinely untrusted-input instance of the download-strategy argument-injection class: a benign formula pointing at a malicious or compromised svn repository is sufficient — no malicious formula content is required. (Reachable when the formula uses svn's multi-revision spec,revisions:, which is what triggers the externals walk inclone_repo; the default/single-revision:svn path does not iterate externals.)Details
Sink chain in
Library/Homebrew/download_strategy/subversion_download_strategy.rb::60svn propget svn:externals <@url>reads the server-controlled externals property.:62name, url = line.split(/\s+/)parses each external (the external URL is server-supplied).:116fetch_repo(..., external_url, ...)→:91command! "svn", args: ["checkout", url, target, *args]—urlis the first positional aftercheckout, with no--before it.A dash-leading
svn:externalsURL (for example--config-dir=<dir>) is parsed bysvnas an option. The same:91sink also takes the formula-author@url; that variant is formula-author-controlled and is reported separately as hardening parity. Thesvn:externalsvector here is the server-supplied, advisory-grade one.The reporter recommends passing
--before the URL/target in thesvn checkoutinvocation (:91) and rejecting dash-leadingsvn:externalsURLs parsed at:62. Final severity and remediation are the PSRT's to decide.PoC
Loopback/synthetic. Driving the real HEAD strategy, a server-supplied
svn:externalsvalue of--config-dir=<dir>reachessvn checkoutin option position andsvnacts on it (the named config directory is created/populated) — captured via the real argv plus the on-disk side effect. Negative controls: a benign (non-dash) externals URL is positional with no effect; a---guarded checkout makes the token positional (rejected as a non-URL). (Full recorded stdout available on request / in the private review bundle.)Impact
A malicious or compromised Subversion server (or a MITM of a plain
svn:///http://repo) injectssvnclient options during a Homebrew download via thesvn:externalsproperty — without any malicious formula. Who is impacted: a user installing a formula that uses svn's multi-revision spec (revisions:) against an svn source whosesvn:externalsare attacker-influenced. Bounded to what an injectedsvnoption can do (for example config-dir redirection / behaviour change); no direct command execution was reached. CWE-88 (Argument Injection).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.
bc237f676c, sink re-verified unchanged (emptygit diff) at master HEADc0ed315adb.svn:externalsURL is a dash-leadingsvnoption,brew fetch, and assert the option reachessvn checkoutin option position via the real argv plus its on-disk side effect. Full prompt/agent logs are available to the PSRT on request.