Make WordPress Core


Ignore:
Timestamp:
08/04/2026 07:25:22 AM (2 months ago)
Author:
westonruter
Message:

XML-RPC: Validate the attachment data in mw_newMediaObject().

Passing anything other than a struct as the fourth argument caused a fatal error, and because the struct was read before the login was attempted, an unauthenticated request was enough to trigger it.

Read and validate the struct only once the request is authenticated and the upload_files capability is confirmed, as every other method on the server does, and reject a call with too few arguments using minimum_args(). The name, type and bits members must all be strings: a struct sent for bits reached fwrite() by way of wp_upload_bits() and threw a TypeError, while one sent for type survived sanitize_mime_type() to reach the database as the attachment's post MIME type. A name left empty by sanitize_file_name() is now reported as a malformed request too, rather than as the server failure wp_upload_bits() produced for it.

The fourth argument is expanded into a nested hash in the documentation, covering the previously undocumented post_id member. Tests cover each rejected shape, the optional members that remain tolerated when absent, and the ordering of the login and capability checks ahead of the validation.

Developed in ​https://github.com/WordPress/wordpress-develop/pull/12482.
Follow-up to r32579, r53881.

Props josephscott, westonruter, mukesh27.
See #65600.
Fixes #65611.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-xmlrpc-server.php

    r62933 r63006  
    64416441         *
    64426442         * @param array $args {
    6443          *     Method arguments. Note: arguments must be ordered as documented.
     6443         *     Method arguments. Note: top-level arguments must be ordered as documented.
    64446444         *
    64456445         *     @type int    $0 Blog ID (unused).
    64466446         *     @type string $1 Username.
    64476447         *     @type string $2 Password.
    6448          *     @type array  $3 Data.
     6448         *     @type array  $3 {
     6449         *         Data for the file to upload.
     6450         *
     6451         *         @type string $name    File name. Sanitized with sanitize_file_name().
     6452         *         @type string $type    Optional. File MIME type, stored as the attachment's
     6453         *                               post MIME type. Default empty string.
     6454         *         @type string $bits    Optional. File contents. Default empty string.
     6455         *         @type int    $post_id Optional. ID of the post to attach the file to.
     6456         *                               Default 0.
     6457         *     }
    64496458         * }
    64506459         * @return array|IXR_Error
    64516460         */
    64526461        public function mw_newMediaObject( $args ) {
     6462                if ( ! $this->minimum_args( $args, 4 ) ) {
     6463                        return $this->error;
     6464                }
     6465
    64536466                $username = $this->escape( $args[1] );
    64546467                $password = $this->escape( $args[2] );
    64556468                $data     = $args[3];
    64566469
    6457                 $name = sanitize_file_name( $data['name'] );
    6458                 $type = $data['type'];
    6459                 $bits = $data['bits'];
    6460 
    64616470                $user = $this->login( $username, $password );
    64626471                if ( ! $user ) {
    … …  
    64716480                        return $this->error;
    64726481                }
     6482
     6483                if (
     6484                        ! is_array( $data ) ||
     6485                        ! is_string( $data['name'] ?? null ) ||
     6486                        ! is_string( $data['type'] ?? '' ) ||
     6487                        ! is_string( $data['bits'] ?? '' )
     6488                ) {
     6489                        return new IXR_Error( 400, __( 'Invalid attachment data.' ) );
     6490                }
     6491
     6492                $name = sanitize_file_name( $data['name'] );
     6493
     6494                // A name consisting only of characters the sanitizer strips leaves nothing to write to.
     6495                if ( '' === $name ) {
     6496                        return new IXR_Error( 400, __( 'Invalid attachment data.' ) );
     6497                }
     6498
     6499                $type = $data['type'] ?? '';
     6500                $bits = $data['bits'] ?? '';
    64736501
    64746502                if ( is_multisite() && upload_is_user_over_quota( false ) ) {
Note: See TracChangeset for help on using the changeset viewer.