Skip to content

Security: add allowed_classes to Form::getSessionValidationResult() unserialize()#11985

Open
XananasX7 wants to merge 1 commit into
silverstripe:6from
XananasX7:security-form-unserialize-allowed-classes
Open

Security: add allowed_classes to Form::getSessionValidationResult() unserialize()#11985
XananasX7 wants to merge 1 commit into
silverstripe:6from
XananasX7:security-form-unserialize-allowed-classes

Conversation

@XananasX7

Copy link
Copy Markdown

Summary

Add explicit allowed_classes restriction to the unserialize() call in Form::getSessionValidationResult().

Vulnerability

Form::getSessionValidationResult() (Form.php line 505) deserializes a ValidationResult from session storage without an allowed_classes restriction:

return unserialize($resultData ?? '');

The session data is user-controlled (read from FormInfo.{FormName}.result in the user's session). An attacker who can control session contents — via session fixation, a storage backend compromise, or a chained injection bug — can supply a crafted serialized payload that instantiates arbitrary PHP classes, exploiting gadget chains present in the application's dependencies.

Fix

Restrict deserialization to only the expected class:

return unserialize($resultData ?? '', ['allowed_classes' => [ValidationResult::class]]);

The deserialized value is always expected to be a ValidationResult. The setSessionValidationResult() method on the same class only ever stores a ValidationResult object, confirming the allowlist is complete.

References

…nserialize()

Form::getSessionValidationResult() deserializes a ValidationResult object
stored in the user session without restricting allowed_classes. Since PHP
session data can be influenced by an attacker (e.g. session fixation,
session storage compromise, or a separate injection bug), this creates a
PHP Object Injection (POI) vector where an attacker can craft a serialized
payload containing arbitrary class instances.

The deserialized value is always expected to be a ValidationResult, so add
an explicit allowed_classes allowlist:

    unserialize($resultData, ['allowed_classes' => [ValidationResult::class]])

This limits instantiation to only the expected class, preventing exploitation
via gadget chains even if an attacker controls the session content.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant