Commit 8d292297f2 for wordpress.org
commit 8d292297f22459138dbf900a2ac90e066ef85c6c
Author: westonruter <westonruter@git.wordpress.org>
Date: Wed Sep 23 19:06:47 2026 +0000
XML-RPC: Return faults for malformed multicall requests.
Previously, a malformed `system.multicall` request could cause a fatal error instead of an XML-RPC fault. `IXR_Server::multiCall()` assumed each entry was a struct with a `methodName` and passed its `params` straight through to `IXR_Server::call()`, which called `count()` on them without checking for an array. On PHP 8 this resulted in a `TypeError` for non-array params.
Now `IXR_Server::multiCall()` returns a `-32600` fault when its argument is not an array, and each entry that is not a struct with a string `methodName` gets its own `-32600` fault, while the remaining calls continue to run. Non-array params get a `-32602` fault, and missing params default to an empty array. Additionally, `IXR_Server::call()` now only unwraps a single parameter when the params are a list, so that a struct with a single member is passed to the method intact rather than as `null`.
Types are also added for `IXR_Server::multiCall()` and `IXR_Error` to aid static analysis.
Developed in https://github.com/WordPress/wordpress-develop/pull/13663.
Props josephscott, westonruter.
See #66168, #65817.
Fixes #66160.
Built from https://develop.svn.wordpress.org/trunk@63901
git-svn-id: http://core.svn.wordpress.org/trunk@63070 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/IXR/class-IXR-error.php b/wp-includes/IXR/class-IXR-error.php
index 660f7d1091..f921c94cdf 100644
--- a/wp-includes/IXR/class-IXR-error.php
+++ b/wp-includes/IXR/class-IXR-error.php
@@ -8,12 +8,22 @@
*/
class IXR_Error
{
+ /**
+ * @var int
+ */
var $code;
+
+ /**
+ * @var string
+ */
var $message;
- /**
- * PHP5 constructor.
- */
+ /**
+ * PHP5 constructor.
+ *
+ * @param int $code Fault code.
+ * @param string $message Fault string.
+ */
function __construct( $code, $message )
{
$this->code = $code;
@@ -22,6 +32,9 @@ class IXR_Error
/**
* PHP4 constructor.
+ *
+ * @param int $code Fault code.
+ * @param string $message Fault string.
*/
public function IXR_Error( $code, $message ) {
self::__construct( $code, $message );
diff --git a/wp-includes/IXR/class-IXR-server.php b/wp-includes/IXR/class-IXR-server.php
index e329602910..e11f40fbe7 100644
--- a/wp-includes/IXR/class-IXR-server.php
+++ b/wp-includes/IXR/class-IXR-server.php
@@ -92,7 +92,7 @@ EOD;
$method = $this->callbacks[$methodname];
// Perform the callback and send the response
- if (count($args) == 1) {
+ if (is_array($args) && count($args) == 1 && array_key_exists(0, $args)) {
// If only one parameter just send that instead of the whole array
$args = $args[0];
}
@@ -194,14 +194,42 @@ EOD;
return array_reverse(array_keys($this->callbacks));
}
+ /**
+ * Handles a system.multicall request.
+ *
+ * @param array[] $methodcalls List of method call structs, each with a methodName and optional params.
+ * @return IXR_Error|array[] Error if the method calls are not an array, otherwise a list of results,
+ * each either a fault struct or a single-element array wrapping the result.
+ *
+ * @phpstan-param list<array{ methodName: string, params?: array<mixed> }> $methodcalls
+ * @phpstan-return IXR_Error|list<array{ faultCode: int, faultString: string }|array{ mixed }>
+ */
function multiCall($methodcalls)
{
// See http://www.xmlrpc.com/discuss/msgReader$1208
+ if (!is_array($methodcalls)) {
+ return new IXR_Error(-32600, 'server error. invalid xml-rpc. system.multicall expects an array of method calls');
+ }
+
$return = array();
foreach ($methodcalls as $call) {
+ // Each call must be a struct naming the method to call.
+ if (!is_array($call) || !isset($call['methodName']) || !is_string($call['methodName'])) {
+ $return[] = array(
+ 'faultCode' => -32600,
+ 'faultString' => 'server error. invalid xml-rpc. Each multicall entry must be a struct with a string methodName'
+ );
+ continue;
+ }
+
$method = $call['methodName'];
- $params = $call['params'];
- if ($method == 'system.multicall') {
+ $params = array();
+ if (isset($call['params'])) {
+ $params = $call['params'];
+ }
+ if (!is_array($params)) {
+ $result = new IXR_Error(-32602, 'server error. invalid method parameters. Each multicall entry params must be an array');
+ } else if ($method == 'system.multicall') {
$result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
} else {
$result = $this->call($method, $params);
diff --git a/wp-includes/version.php b/wp-includes/version.php
index a0fe0d7425..96b75ca898 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-63900';
+$wp_version = '7.2-alpha-63901';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.