[wp-trac] [WordPress Trac] #37757: Add `allowed_classes` to `maybe_unserialize` When WordPress is running on PHP 7+

WordPress Trac noreply at wordpress.org
Fri Feb 21 09:01:01 UTC 2025


#37757: Add `allowed_classes` to `maybe_unserialize` When WordPress is running on
PHP 7+
-------------------------------------------------+-------------------------
 Reporter:  chrisguitarguy                       |       Owner:  (none)
     Type:  enhancement                          |      Status:  new
 Priority:  normal                               |   Milestone:  Awaiting
                                                 |  Review
Component:  Security                             |     Version:
 Severity:  normal                               |  Resolution:
 Keywords:  has-patch has-unit-tests 2nd-        |     Focuses:
  opinion                                        |
-------------------------------------------------+-------------------------

Comment (by FrancescoCarlucci):

 Replying to [comment:12 johnbillion]:

 Thanks for the feedback!

 > If a plugin serializes `class Foo {}`, unserialization will break if
 another plugin hooks into the `maybe_unserialize_allowed_classes` filter
 and adds `Bar` to the resulting array of classes names, because `Foo`
 won't be present.


 Of course, but if we initialize the filter as `false`, it will not break
 everything while still allowing developers to harden their WP installation
 without editing the core.

 It would be developers responsibility to check if there are serialized
 classes - if they decide to activate the filter.

 > This will also break unserialization of all WordPress core classes and
 `stdClass` instances that are serialized but aren't present in the
 `maybe_unserialize_allowed_classes` filter return value.

 Are there serialized classes in WP core passed to maybe_unserialize? I
 can't find any: https://github.com/search?q=repo%3AWordPress%2Fwordpress-
 develop%20maybe_unserialize&type=code

 > the original patch on this ticket proposes adding an $options argument
 to maybe_unserialize() instead

 As far as I understand, the original patch is pretty much similar, but
 gives you flexibility on the options to pass, which is good. unserialize()
 at the moment only takes `allowed_classes ` and  `max_depth`, but maybe in
 the future there may be more, so I agree on making the filter act on
 $options.

 > Before doing that though, I think we need to assess the exact threat and
 whether introducing that argument would address it.

 The threat is that every time maybe_unserialize() takes untrusted data as
 an input, PHP object injection is possible and this isn't any good :) If a
 POP Chain is present, it can lead to RCE and arbitrary file deletion. In
 plain English, if a Class that contains a magic method gets unserialized,
 the magic method gets executed. Even the WP Core had a POP chain for a
 while: https://www.wordfence.com/blog/2023/12/psa-critical-pop-chain-
 allowing-remote-code-execution-patched-in-wordpress-6-4-2/

 POP Chains are not rare in libraries as well and they are not considered a
 vulnerability by itself, because they are exploitable only through PHP
 Object Injection, which indeed is considered a vulnerability.

 "every time maybe_unserialize() takes untrusted data as an input" - this
 happens often, because plugin developers tend to use core functions on
 data that are not 100% trusted, a few CVEs to support this:

 - CVE-2024-1770
 - CVE-2024-2693
 - CVE-2024-2694
 - Hundreds more...

 Let me know if it makes any sense!

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/37757#comment:13>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list