Skip to content

[Security] Restrict unserialize() allowed_classes in TaskProcessing distributed cache#60883

Open
XananasX7 wants to merge 1 commit into
nextcloud:masterfrom
XananasX7:security/taskprocessing-cache-unserialize
Open

[Security] Restrict unserialize() allowed_classes in TaskProcessing distributed cache#60883
XananasX7 wants to merge 1 commit into
nextcloud:masterfrom
XananasX7:security/taskprocessing-cache-unserialize

Conversation

@XananasX7
Copy link
Copy Markdown

Summary

TaskProcessing\Manager::getAvailableTaskTypes() serializes ShapeDescriptor, ShapeEnumValue, and EShapeType objects into the distributed cache and reads them back with bare unserialize() — no allowed_classes restriction.

An attacker who can write to the distributed cache backend can inject a crafted PHP serialized payload containing a gadget chain and achieve Remote Code Execution when getAvailableTaskTypes() is next called.

Attack scenario

  1. Attacker can write to the distributed cache backend (unauthenticated Redis, SSRF to cache server, or a cache-poisoning vulnerability in the application).
  2. Attacker injects a serialized payload using gadget classes loaded by Nextcloud/Symfony (e.g., Monolog, Doctrine, or any other library with exploitable __destruct/__wakeup).
  3. On the next getAvailableTaskTypes() call, the gadget chain fires → RCE.

Fix

Restrict allowed_classes to the three value-object types that are actually stored in this cache entry (ShapeDescriptor, ShapeEnumValue, EShapeType). Any other class in the serialized string becomes a harmless __PHP_Incomplete_Class.

Files changed

  • lib/private/TaskProcessing/Manager.php — add explicit allowed_classes to unserialize()

getAvailableTaskTypes() stores a serialized array of ShapeDescriptor,
ShapeEnumValue, and EShapeType values in the distributed cache and reads
them back with bare unserialize() — no allowed_classes restriction.

An attacker who can write to the distributed cache backend (e.g., via an
unauthenticated Redis instance, SSRF to the cache server, or a cache-poisoning
vulnerability) can inject a crafted PHP serialized payload containing a gadget
chain and achieve Remote Code Execution when getAvailableTaskTypes() is next
called.

Restrict allowed_classes to the three value-object types actually stored in
this cache entry (ShapeDescriptor, ShapeEnumValue, EShapeType). Any other
class in the serialized string will become a harmless __PHP_Incomplete_Class
without executing constructors or magic methods.
@XananasX7 XananasX7 requested a review from a team as a code owner May 31, 2026 02:47
@XananasX7 XananasX7 requested review from Altahrim, CarlSchwan, leftybournes and salmart-dev and removed request for a team May 31, 2026 02:47
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