[wp-trac] [WordPress Trac] #60585: Recursion in WP_REST_Posts_Controller schema

WordPress Trac noreply at wordpress.org
Tue Feb 20 17:45:04 UTC 2024


#60585: Recursion in WP_REST_Posts_Controller schema
--------------------------+-----------------------------
 Reporter:  derrickkoo    |      Owner:  (none)
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  REST API      |    Version:  6.4.3
 Severity:  normal        |   Keywords:  needs-testing
  Focuses:  performance   |
--------------------------+-----------------------------
 In the schema definition for the `WP_REST_Posts_Controller` class, any
 attribute which invokes a array-like callable with `$this` for its
 `validate_callback` or `sanitize_callback` option will result in a
 recursive instance of the `WP_REST_Posts_Controller` class to be attached
 to that schema definition. Here's an example of such a callable that
 causes this issue (code pasted below; see the value of
 `sanitize_callback`): https://github.com/WordPress/WordPress/blame/master
 /wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php#L2288


 {{{#!php
 'slug'         => array(
         'description' => __( 'An alphanumeric identifier for the post
 unique to its type.' ),
         'type'        => 'string',
         'context'     => array( 'view', 'edit', 'embed' ),
         'arg_options' => array(
                 'sanitize_callback' => array( $this, 'sanitize_slug' ),
         ),
 ),
 }}}

 For most sites this doesn't seem to cause any issues, but on sites that
 register a lot of custom meta on the `post` CPT, because each registered
 meta key adds its own schema attribute, this can result in a huge
 `WP_REST_Posts_Controller` object which can potentially cause an
 unexpected response to `POST` requests to the `posts` endpoint. Curiously,
 this doesn't seem to cause an OOM error in my testing, but instead returns
 a `403` response with a generic `The link you followed has expired` error,
 which sounds more like an expired nonce error than a memory error.

 This can be replicated and seen in a couple of ways:

 1. Using `wp shell` to instantiate the `WP_REST_Posts_Controller` class
 for the `posts` endpoint and fetching its schema:


 {{{#!php
 wp> $controller = new WP_REST_Posts_Controller( 'post' );
 wp> $controller->get_item_schema();
 }}}

 The output of `get_item_schema()` will return a schema object showing the
 recursive instances of `WP_REST_Posts_Controller` where those callables
 are defined.

 2. By making a `POST` request to the `posts` endpoint, hooking into the
 `rest_insert_post` action hook (see:
 https://developer.wordpress.org/reference/hooks/rest_insert_this-
 post_type/) and logging the `$request` argument. The
 `['attributes']['args']` property will contain the full schema and show
 the recursion for any schema attribute invoking a callable using `$this`.

 Potential (untested) solution: instead of invoking callables using
 `$this`, convert the callable methods to static methods on the
 `WP_REST_Posts_Controller` class or its parent, and invoke using `[
 __CLASS__, 'method_name' ]` to avoid recursion.

 Tested with v6.4.3 and v5.9.9 so far.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/60585>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list