Skip to content

Fix urlencoded POST registering max_input_vars + 1 variables - #24773

Open
Marti2203 wants to merge 1 commit into
php:PHP-8.4from
Marti2203:fix-post-max-input-vars-off-by-one
Open

Marti2203 wants to merge 1 commit into
php:PHP-8.4from
Marti2203:fix-post-max-input-vars-off-by-one

Conversation

@Marti2203

Copy link
Copy Markdown
Contributor

An application/x-www-form-urlencoded POST body with more than max_input_vars variables puts max_input_vars + 1 entries into $_POST. GET, cookies and multipart/form-data stop at exactly max_input_vars.

Reproducer

php-cgi, max_input_vars=1000, with 1001 variables each in the query string, the Cookie header and the urlencoded body:

$ php-cgi -n -d max_input_vars=1000 -d output_buffering=4096 count.php   # count.php: echo count($_GET), count($_POST), count($_COOKIE)
Warning: PHP Request Startup: Input variables exceeded 1000. ... (x3)
GET=1000 POST=1001 COOKIE=1000

The same count shows up in #20456 ("Total test values: 1001").

Cause

add_post_vars() checks the limit only after add_post_var() has already registered the variable:

while (add_post_var(arr, vars, eof)) {
	if (++vars->cnt > max_vars) {
		/* warning */
		return FAILURE;
	}

php_default_treat_data() (GET/cookies) and rfc1867.c check the count before registering.

Fix

add_post_vars() passes vars->cnt < max_vars to add_post_var(). Once the limit has been reached, add_post_var() still reports that a variable is present but does not register it. The warning text and the point where parsing stops do not change. With the fix the output above becomes GET=1000 POST=1000 COOKIE=1000. A body of exactly 1000 variables still gives 1000 entries and no warning, and max_input_vars=0 now gives 0 entries for POST, as it already did for GET.

Tests

  • New tests/basic/max_input_vars_post_urlencoded.phpt (max_input_vars=5, 6 POST variables): before the fix $_POST has 6 entries and the test fails; with the fix it has 5 and the test passes.
  • tests/basic, ext/standard/tests/http (including request_parse_body), sapi/cgi/tests, sapi/cli/tests: 277 passed, 68 skipped, 0 failed. Zend/tests/oom_request_parsing.phpt also passes. (Non-debug --disable-all --enable-cli --enable-cgi build.)

This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually.

add_post_vars() checked the max_input_vars limit only after
add_post_var() had already registered the variable, so an
application/x-www-form-urlencoded body with more than max_input_vars
variables produced max_input_vars + 1 entries in $_POST (1001 with
the default setting). The GET, cookie and multipart/form-data paths
stop at exactly max_input_vars.

Skip registering the variable once the limit has been reached; the
warning is emitted at the same point as before.
@Marti2203
Marti2203 requested a review from bukka as a code owner October 27, 2026 03:45
@ArtUkrainskiy

Copy link
Copy Markdown
Contributor

I checked this with and without the patch. Without it, 6 vars at max_input_vars=5 land 6 entries in $_POST. With the patch it caps at 5, same as GET and multipart. The loop still terminates at the limit. LGTM.

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