Make WordPress Core

Opened 9 months ago

Last modified 7 weeks ago

#61061 new defect (bug)

PHP Warning with invalid JSON input

Reported by: dd32's profile dd32 Owned by:
Milestone: 6.8 Priority: low
Severity: normal Version:
Component: REST API Keywords: has-patch has-unit-tests
Focuses: rest-api Cc:

Description

A request such as the following will generate a PHP Warning:

curl https://example.org/wp-json/wp/v2/users/1 --data '"+response.write(document.domain)+"' -H 'Content-Type: application/json'

The warning:

E_WARNING: Invalid argument supplied for foreach() in wp-includes/rest-api/class-wp-rest-request.php:816

The relevant part of the backtrace:

[24-Apr-2024 04:11:35 UTC] PHP  10. WP_REST_Server->serve_request($path = '/wp/v2/users/1') wp-includes/rest-api.php:428
[24-Apr-2024 04:11:35 UTC] PHP  11. WP_REST_Server->dispatch($request = class WP_REST_Request { protected $method = 'POST'; protected $params = ['URL' => ['id' => '1'], 'GET' => [], 'POST' => [], 'FILES' => [], 'JSON' => '+response.write(document.domain)+', 'defaults' => []]; protected $headers = ['content_type' => [0 => 'application/json'] ]; protected $body = '"+response.write(document.domain)+"'; protected $route = '/wp/v2/users/1'; protected $attributes = ['methods' => ['POST' => TRUE, 'PUT' => TRUE, 'PATCH' => TRUE], 'accept_json' => FALSE, 'accept_raw' => FALSE, 'show_in_index' => TRUE,  [.......]; protected $parsed_json = TRUE; protected $parsed_body = FALSE }) wp-includes/rest-api/class-wp-rest-server.php:439
[24-Apr-2024 04:11:35 UTC] PHP  12. WP_REST_Request->sanitize_params() wp-includes/rest-api/class-wp-rest-server.php:1056

Change History (12)

#1 @dd32
9 months ago

Of course, this is actually a valid JSON input.

These are also valid, and produce the same result.

curl https://example.org/wp-json/wp/v2/users/1 --data '"foobar"' -H 'Content-Type: application/json'
curl https://example.org/wp-json/wp/v2/users/1 --data '1' -H 'Content-Type: application/json'

It seems that the expected outcome here is to simply skip sanitisation of the param, ultimately a missing field should be picked up by the schema of the API endpoint, and the endpoint may expect/handle a string/numeric input in the field.

See attached.

This ticket was mentioned in PR #6491 on WordPress/wordpress-develop by @dd32.


9 months ago
#2

  • Keywords has-patch added

#3 @antonvlasenko
7 months ago

Test Report

This report validates that the indicated patch addresses the issue.

Patch tested: https://github.com/WordPress/wordpress-develop/pull/6491

Environment

  • WordPress: 6.6-beta3-58440-src
  • PHP: 7.3.33
  • Server: Apache/2.4.57 (Unix) PHP/7.3.33
  • Database: mysqli (Server: 5.7.43 / Client: mysqlnd 5.0.12-dev)
  • Browser: Safari 17.5 (macOS)
  • Theme: Twenty Twenty-Four 1.1
  • MU-Plugins: None activated
  • Plugins:
    • JSON Basic Authentication 0.1

Actual Results

  • ✅ No error in the debug.log file after applying the patch.

Additional Notes

The curl request used for testing:

curl --user admin:password http://wordpress.test/wp-json/wp/v2/users/1 --data '1' -H 'Content-Type: application/json'

Supplemental Artifacts

Before applying the patch, the following error was recorded in the debug.log file:

[03-Jul-2024 14:32:18 UTC] PHP Warning:  Invalid argument supplied for foreach() in /src/wp-includes/rest-api/class-wp-rest-request.php on line 816

#4 @swissspidy
3 months ago

  • Keywords commit added
  • Milestone changed from Awaiting Review to 6.7

@peterwilsoncc commented on PR #6491:


3 months ago
#5

@dd32 Would you be able to add a test for this?

@dd32 commented on PR #6491:


3 months ago
#6

@peterwilsoncc I don't think I'll have time until next week, but I'll see what I can do! I don't actually fully know how to trigger this from within PHP, I just repro'd it with curl and filed 🤷

@peterwilsoncc commented on PR #6491:


3 months ago
#7

Thanks Dion,

I figured out how to test some things but not sure if we'll need more. I added this to tests/phpunit/tests/rest-api/rest-request.php

The one thing I am unsure of is whether strings are intended to be valid. @TimothyBJacobs, @kadamwhite Do either of you know?

/**
 * @ticket 61061
 */
public function test_sanitize_params_with_string_parameters() {
        $this->request->set_url_params( 'foobar' );

        $this->request->set_attributes(
                array(
                        'args' => array(
                                'someinteger' => array(
                                        'sanitize_callback' => 'absint',
                                ),
                                'somestring'  => array(
                                        'sanitize_callback' => 'absint',
                                ),
                        ),
                )
        );

        $this->request->sanitize_params();

        $this->assertSame( 'foobar', $this->request->get_url_params() );
}

/**
 * @ticket 61061
 */
public function test_has_valid_params_with_string_parameter_and_required_attribute() {
        $this->request->set_url_params( 'foobar' );

        $this->request->set_attributes(
                array(
                        'args' => array(
                                'someinteger' => array(
                                        'sanitize_callback' => 'absint',
                                        'required'          => true,
                                ),
                        ),
                )
        );

        $this->assertWPError( $this->request->has_valid_params() );
}

/**
 * @ticket 61061
 */
public function test_has_valid_params_with_string_parameter_without_required_attribute() {
        $this->request->set_url_params( 'foobar' );

        $this->request->set_attributes(
                array(
                        'args' => array(
                                'someinteger' => array(
                                        'sanitize_callback' => 'absint',
                                ),
                        ),
                )
        );

        $this->assertTrue( $this->request->has_valid_params() );
}

@antonvlasenko commented on PR #6491:


3 months ago
#8

I'm currently working on adding more tests to this PR (unless @dd32 has any objections).

This ticket was mentioned in Slack in #core by chaion07. View the logs.


3 months ago

This ticket was mentioned in Slack in #core by stoyangeorgiev. View the logs.


3 months ago

#11 @peterwilsoncc
3 months ago

  • Keywords needs-refresh needs-unit-tests added; commit removed
  • Milestone changed from 6.7 to 6.8

I've removed the commit keyword and moved this off the release as @antonvlasenko picked up some potentially related issues while working on some tests.

This ticket was mentioned in PR #7961 on WordPress/wordpress-develop by @sukhendu2002.


7 weeks ago
#12

  • Keywords has-unit-tests added; needs-refresh needs-unit-tests removed
Note: See TracTickets for help on using tickets.