Make WordPress Core

Opened 5 weeks ago

Closed 2 weeks ago

#65611 closed defect (bug) (fixed)

XML-RPC: mw_newMediaObject, check 4th arg is an array

Reported by: josephscott Owned by: westonruter
Priority: normal Milestone: 7.1
Component: XML-RPC Version:
Severity: normal Keywords:
Cc: Focuses:

Description

The current mw_newMediaObject XML-RPC function will generate a PHP fatal error when given something unexpected. The problem can be easily reproduced with:

curl -v -H 'Content-Type: text/xml' http://localhost:8889/xmlrpc.php \
--data '<?xml version="1.0"?>
  <methodCall>
    <methodName>wp.uploadFile</methodName>
    <params>
      <param><value><int>1</int></value></param>
      <param><value><string>anyuser</string></value></param>
      <param><value><string>anypass</string></value></param>
      <param><value><string>not-a-struct</string></value></param>
    </params>
  </methodCall>'

That generates a fatal error condition, with a HTTP 500 response:

* Host localhost:8889 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8889...
* Connected to localhost (::1) port 8889
> POST /xmlrpc.php HTTP/1.1
> Host: localhost:8889
> User-Agent: curl/8.7.1
> Accept: */*
> Content-Type: text/xml
> Content-Length: 359
> 
* upload completely sent off: 359 bytes
< HTTP/1.1 500 Internal Server Error
< Server: nginx/1.29.7
< Content-Type: text/xml; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/8.3.30
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
< Date: Fri, 10 Jul 2026 20:58:14 +0000
< 
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <fault>
    <value>
      <struct>
        <member>
          <name>faultCode</name>
          <value><int>500</int></value>
        </member>
        <member>
          <name>faultString</name>
          <value><string>&lt;p&gt;There has been a critical error on this website.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://wordpress.org/documentation/article/faq-troubleshooting/&quot;&gt;Learn more about troubleshooting WordPress.&lt;/a&gt;&lt;/p&gt;</string></value>
        </member>
      </struct>
    </value>
  </fault>
</methodResponse>
* Connection #0 to host localhost left intact

In general WordPress shouldn't fall over with a fatal error when given something unexpected. I have a small patch to catch this condition, avoid the fatal error, and return something a bit more helpful ( with HTTP 200 ):

* Host localhost:8889 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8889...
* Connected to localhost (::1) port 8889
> POST /xmlrpc.php HTTP/1.1
> Host: localhost:8889
> User-Agent: curl/8.7.1
> Accept: */*
> Content-Type: text/xml
> Content-Length: 359
> 
* upload completely sent off: 359 bytes
< HTTP/1.1 200 OK
< Server: nginx/1.29.7
< Content-Type: text/xml; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/8.3.30
< Date: Fri, 10 Jul 2026 21:07:57 +0000
< 
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <fault>
    <value>
      <struct>
        <member>
          <name>faultCode</name>
          <value><int>400</int></value>
        </member>
        <member>
          <name>faultString</name>
          <value><string>Invalid attachment data.</string></value>
        </member>
      </struct>
    </value>
  </fault>
</methodResponse>
* Connection #0 to host localhost left intact

The wp.uploadFile docs ( https://codex.wordpress.org/XML-RPC_WordPress_API/Media#wp.uploadFile ) indicate it needs to be a struct, as do the code comments ( https://github.com/WordPress/wordpress-develop/blob/a71fb9b8bdd9da42832ea07e841921ff1b2b4f87/src/wp-includes/class-wp-xmlrpc-server.php#L6429 ). We should enforce that and avoid a fatal error.

Change History (7)

#1 @josephscott
5 weeks ago

I've got a similar fix for another XML-RPC method in https://core.trac.wordpress.org/ticket/65600

@josephscott commented on PR #12482:


5 weeks ago
#2

The test failures appear unrelated to this change.

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


5 weeks ago

#4 @westonruter
5 weeks ago

  • Milestone Awaiting Review7.1
  • Owner set to westonruter
  • Status newreviewing

#5 @josephscott
3 weeks ago

@westonruter are there any changes that you want to see on this?

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


2 weeks ago

#7 @westonruter
2 weeks ago

  • Resolutionfixed
  • Status reviewingclosed

In 63006:

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.

Note: See TracTickets for help on using tickets.