Why Docket Cache No Longer Unserializes Strings
On 14 October 2026 we released Docket Cache 26.04.10, a security release. Its most important change is small to describe. When a plugin caches a piece of text, Docket Cache now gives back exactly the same text. This post explains what changed, why it matters, and what you need to do. The short answer to the last part is to update to the latest version, 26.04.11.
What serialize means#
PHP can turn a value, such as an array or an object, into a line of text with its serialize() function, so the value can be saved in a file or a database. The unserialize() function turns the text back into the value. WordPress uses this a lot. For example, it saves many settings in the database as serialized text.
serialize( array( 'one' ) );
// 'a:1:{i:0;s:3:"one";}'
What Docket Cache used to do#
Up to version 26.04.09, Docket Cache tried to be helpful. When a plugin cached a piece of text that looked like serialized data, Docket Cache unserialized it, when saving it or when reading it back. That caused two problems.
- The data changed. A plugin stored a piece of text and got back an array or an object. That is not what it asked for, and it is not what WordPress does without an object cache.
- It was a security risk.
unserialize()can create PHP objects. If text from outside the site, such as something a visitor typed, ever reached the cache, reading it back could create objects the site never meant to create. This kind of problem is called PHP object injection. On its own it may do nothing, but together with other code on a site, it can be used to attack the site.
What changed in 26.04.10#
Docket Cache now returns cached text exactly as it was stored. It never unserializes text that a plugin or WordPress gave it.
wp_cache_set( 'example', 'a:1:{i:0;s:3:"one";}', 'my-plugin' );
$value = wp_cache_get( 'example', 'my-plugin' );
// 26.04.09 and older: array( 'one' )
// 26.04.10 and later: 'a:1:{i:0;s:3:"one";}'
Docket Cache still unserializes data in two cases. Both are safe, because the data never came from a plugin as text.
- data that Docket Cache serialized itself, from an array it was given
- rows that Docket Cache copied from the WordPress database when the cache was set up, which WordPress itself would unserialize with
get_option()
Docket Cache also now checks that a cached file really belongs to the key and group that were asked for, before it returns the value.
The Data Storage page in the documentation explains each stored type in detail.
Why this does not break WordPress#
WordPress does not rely on the cache to unserialize anything. For example, get_option() caches the text from the database as it is, and then calls maybe_unserialize() itself after reading it from the cache. So returning the text unchanged gives the same result as WordPress without an object cache.
If you wrote a plugin that cached serialized text and expected an array back, store the array instead. Docket Cache keeps arrays as plain PHP, so they load fast. Or call maybe_unserialize() yourself after wp_cache_get(), as WordPress does.
Do you need to do anything?#
Update Docket Cache to the latest version, 26.04.11, from the Plugins screen or from WordPress.org. It includes every fix in 26.04.10, and also fixes a problem that 26.04.10 introduced, where some transients copied from the database came back as serialized text.
You do not need to clear the cache. Each cache file has a format version. When Docket Cache reads a file written by an older version, it deletes the file and builds the value again, so your cache refills by itself after the update.
Other fixes in 26.04.10#
The same release has more security fixes.
- The WP-CLI OPcache secret is now kept in a PHP file, not in a file that the web could read.
- Clearing a single cache file now checks the file name, so it cannot reach files outside the cache folder.
- Turning Suspend Object Cache on or off now goes through a checked admin action.
- An admin notice is now built in a way that cannot run injected script.
runtime.phponly accepts the values it expects, which are on, off or a number.- Cookies are only sent with requests to the site itself, never to Cronbot.
- The output of cron tasks is no longer sent back to Cronbot.
- Cron event arguments and names are escaped in the Cronbot table.
- The option that caches the replies to WordPress's own outgoing HTTP requests now only caches plain GET requests sent without login details or cookies, and never a reply that sets cookies.
- The shared menu cache is not used for visitors who are logged in.
Reporting a security problem#
If you find a security problem in Docket Cache, please email [email protected] instead of posting it on the public support forum, so it can be fixed before it is made public.