Skip to content

Fix downloads.php crash on invalid os parameter#1968

Open
svpernova09 wants to merge 2 commits into
php:masterfrom
svpernova09:downloads-crash-on-invalid-os
Open

Fix downloads.php crash on invalid os parameter#1968
svpernova09 wants to merge 2 commits into
php:masterfrom
svpernova09:downloads-crash-on-invalid-os

Conversation

@svpernova09

Copy link
Copy Markdown

Fix downloads.php crash on invalid os query parameter

Summary

downloads.php throws an uncaught TypeError whenever the os query
parameter is not one of the three whitelisted values (linux, osx,
windows). The value goes straight from $_GET into an array index
($os[$options['os']]['variants']) without validation, so any unexpected
value makes that expression null and blows up array_key_exists().

This is currently the single largest source of PHP fatals on www.php.net:
24,332 fatal errors in a recent 15‑day window of production logs. Almost
entirely from bots and security scanners fuzzing the parameter.

This PR validates os against the whitelist (falling back to the auto‑detected
default), and extracts the option‑resolution logic into a unit‑tested
OptionResolver class following the existing LangChooser pattern.

The bug

downloads.php merges raw $_GET over the defaults and then uses the
attacker‑controlled os value to index the $os config:

$options = array_merge($defaults, $_GET);

if ($auto_osvariant && (!array_key_exists('osvariant', $options) || !array_key_exists($options['osvariant'], $os[$options['os']]['variants']))) {
    $options['osvariant'] = $auto_osvariant;
} elseif (!array_key_exists('osvariant', $options) || !array_key_exists($options['osvariant'], $os[$options['os']]['variants'])) {
    $options['osvariant'] = array_key_first($os[$options['os']]['variants']);
}

If $options['os'] is not a key in $os, then $os[$options['os']] is null,
$os[$options['os']]['variants'] is null, and array_key_exists(..., null)
throws.

Evidence from production logs

The fatal (error.log, client IP redacted):

[Tue Jul 14 01:08:07.933886 2026] [php:error] [pid 1259211:tid 1259211] [client REDACTED] PHP Fatal error:  Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, null given in /var/www/sites/www.php.net/downloads.php:136
Stack trace:
#0 {main}
  thrown in /var/www/sites/www.php.net/downloads.php on line 136

The companion warning emitted immediately before it:

[Tue Jul 14 01:08:07.933846 2026] [php:warn] ... PHP Warning:  Trying to access array offset on null in /var/www/sites/www.php.net/downloads.php on line 136

Behavior for valid input is unchanged.

Testing

  • New: tests/Unit/Downloads/OptionResolverTest.php: 10 tests covering the
    crash repro (?os=<garbage> and ?os[]=array now fall back to the default),
    valid‑input passthrough, variant fallback, $_GET preservation, and
    user‑agent auto‑detection.
  • Verified end‑to‑end against the running site: GET /downloads.php?os=<garbage>,
    ?os[]=x, ?os=windows, and the plain page all return HTTP 200 with the
    form fully rendered; no fatals in the server log.

  Validate the client-supplied ?os= against the whitelist before indexing,
  fixing ~24k/day 'array_key_exists(): ... null given' fatals. Extract the
  resolution into a testable OptionResolver class.
@github-actions

Copy link
Copy Markdown
Contributor

📊 Regression report for commit 70b6307 is at https://web-php-regression-report-pr-1968.preview.thephp.foundation

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview for commit 70b6307 is available at https://web-php-pr-1968.preview.thephp.foundation

@sy-records

Copy link
Copy Markdown
Member

I think we should add a redirect instead of rendering by default.
When an incorrect value is entered, it should redirect to the results of the automatic detection.

https://web-php-pr-1968.preview.thephp.foundation/downloads.php?os=error

@svpernova09

Copy link
Copy Markdown
Author

I think we should add a redirect instead of rendering by default. When an incorrect value is entered, it should redirect to the results of the automatic detection.

https://web-php-pr-1968.preview.thephp.foundation/downloads.php?os=error

Thanks for the feedback, I've added this at the risk of some complexity. If we're happy, I can squash the commits, or we can keep tinkering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants