Skip to content

Security: change PhpSerializeOptions $allowedClasses default to false - #98

Open
XananasX7 wants to merge 4 commits into
laminas:3.3.xfrom
XananasX7:security-change-allowed-classes-default
Open

Security: change PhpSerializeOptions $allowedClasses default to false#98
XananasX7 wants to merge 4 commits into
laminas:3.3.xfrom
XananasX7:security-change-allowed-classes-default

Conversation

@XananasX7

Copy link
Copy Markdown

Summary

Change the default value of PhpSerializeOptions::$allowedClasses from true to false.

Security Motivation

The current default (true) means that when PhpSerialize::unserialize() is called without explicit allowed_classes configuration, PHP will happily instantiate any class available in the autoloader during deserialization. This is the vector for PHP Object Injection (POI) attacks — an attacker who controls the serialized payload can exploit available gadget chains.

This is especially dangerous in the common usage pattern where:

  1. The application stores serialized data in a shared cache backend (Redis, Memcache, file system)
  2. An attacker can influence the cache contents (e.g. cache key injection, SSRF to cache, compromised backend)
  3. The application deserializes without an explicit allowed_classes allowlist

Change

-protected bool|array $allowedClasses = true;
+protected bool|array $allowedClasses = false;

Migration

Applications that legitimately deserialize objects must now opt in explicitly:

// Allow all classes (restore legacy behaviour):
$options->setAllowedClasses(true);

// Allow specific classes only (recommended):
$options->setAllowedClasses([MyModel::class, AnotherClass::class]);

Impact

This is a breaking change for callers that:

  1. Use PhpSerialize without configuring allowed_classes, AND
  2. Expect objects to be deserialized (not just scalars/arrays)

The fix is to add an explicit allowlist at the call site.

Related

renovate Bot and others added 4 commits April 27, 2026 01:31
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Previously, $allowedClasses defaulted to true, allowing any PHP class to
be instantiated during unserialize(). This is unsafe when the serialized
data originates from an untrusted source (e.g. user-controlled cache keys
or session data): an attacker who can control the serialized payload can
trigger PHP Object Injection via available gadget chains.

Change the default to false (deny all classes). Callers that legitimately
need to deserialize objects must now opt in by explicitly setting:

    $options->setAllowedClasses(true);          // allow all (legacy)
    $options->setAllowedClasses([Foo::class]);   // allow specific classes

This is a breaking change for any consumer that relies on the old default
and deserializes objects without configuring allowed_classes — update
those call sites to pass an explicit allowlist.
@arueckauer

Copy link
Copy Markdown
Member

@XananasX7 Thanks for your contribution! After discussing this with the maintainer, we'd like to target this for the 4.0 release. Could you please change the base branch to target 4.x? Also, please take a look at the failing CI builds and update the PR to get the tests green. Let us know if you need any assistance with this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants