Skip to content

CVE-2026-27206: Verified Repro With Script Download

CVE-2026-27206: Zumba JSON Serializer PHP Object Injection

CVE-2026-27206 is verified against zumba/json-serializer · composer. Affected versions: < 3.2.3. Fixed in 3.2.3. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00108.

REPRO-2026-00108 zumba/json-serializer · composer RCE Feb 20, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
8.1
Reproduced in
11m 26s
Tool calls
93
Spend
$0.32
01 · Overview

What Is CVE-2026-27206?

CVE-2026-27206 is a high-severity PHP Object Injection vulnerability in the zumba/json-serializer library, caused by unrestricted class instantiation during JSON deserialization. Pruva reproduced it (reproduction REPRO-2026-00108).

02 · Severity & CVSS

CVE-2026-27206 Severity & CVSS Score

CVE-2026-27206 is rated high severity, with a CVSS base score of 8.1 out of 10.

HIGH threat level
8.1 / 10 CVSS base
Weakness CWE-502 — Deserialization of Untrusted Data

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected zumba/json-serializer Versions

zumba/json-serializer · composer versions < 3.2.3 are affected.

How to Reproduce CVE-2026-27206

$ pruva-verify REPRO-2026-00108
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00108/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-27206

Reproduced by Pruva's autonomous agents — 93 tool calls over 11 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 283 events · 93 tool calls · 11 min
11 minDuration
93Tool calls
61Reasoning steps
283Events
3Dead-ends
Agent activity over 11 min
Support
20
Repro
123
Variant
136
0:0011:26

Root Cause and Exploit Chain for CVE-2026-27206

GHSA-v7m3-fpcr-h7m2: Zumba Json Serializer PHP Object Injection via @type

Summary

The zumba/json-serializer library prior to version 3.2.3 contains a PHP Object Injection vulnerability in its JSON deserialization functionality. The JsonSerializer::unserialize() method accepts a special @type field in JSON that specifies which PHP class to instantiate. In vulnerable versions, there is no validation or restriction on which classes can be specified, allowing an attacker to instantiate arbitrary PHP classes. When combined with classes that have dangerous magic methods like __wakeup() or __destruct(), this can lead to gadget chain attacks and potentially Remote Code Execution (RCE).

Impact

Package: zumba/json-serializer
Affected Versions: < 3.2.3
Patched Version: 3.2.3
CVE: CVE-2026-27206
CVSS Score: 8.1 (HIGH)

Risk Level: High - This vulnerability allows arbitrary class instantiation when attacker-controlled JSON is passed to the deserializer. If the application or its dependencies contain classes with dangerous magic methods (such as __wakeup() or __destruct()), this may lead to:

  • Remote Code Execution (RCE) via gadget chains
  • Data exfiltration
  • File manipulation
  • Denial of service

Prerequisites for Exploitation:

  1. Untrusted/attacker-controlled JSON passed to JsonSerializer::unserialize()
  2. Presence of exploitable classes (gadget chains) in the application or dependencies
Root Cause

The vulnerability exists in the unserializeObject() method in src/JsonSerializer/JsonSerializer.php. When deserializing JSON containing an @type field:

  1. The method extracts the class name from @type without any validation
  2. It checks if the class exists using class_exists($className)
  3. If the class exists, it instantiates the class directly using new $className() or $ref->newInstanceWithoutConstructor()
  4. No check is performed to restrict which classes may be instantiated

Vulnerable code pattern (v3.2.2):

protected function unserializeObject($value)
{
    $className = $value[static::CLASS_IDENTIFIER_KEY]; // @type value
    unset($value[static::CLASS_IDENTIFIER_KEY]);
    
    // ... recursion handling ...
    
    if (!class_exists($className)) {
        throw new JsonSerializerException('Unable to find class ' . $className);
    }
    
    // No allowed class check - ANY class can be instantiated!
    $ref = new ReflectionClass($className);
    $obj = $ref->newInstanceWithoutConstructor();
    // ...
    if (method_exists($obj, '__wakeup')) {
        $obj->__wakeup(); // Magic method called!
    }
}

The Fix (v3.2.3): The fix introduces a setAllowedClasses(?array $allowedClasses) method that allows applications to specify which classes may be instantiated during deserialization. When configured, the unserializeObject() method validates the class name against the allowed list before instantiation.

Fix commit: 88b44c5 Adding method to restrict classes allowed on unserialize

Reproduction Steps

The reproduction script is located at: repro/reproduction_steps.sh

What the script does:

  1. Clones the zumba/json-serializer repository
  2. Checks out the vulnerable version 3.2.2
  3. Installs PHP dependencies via composer
  4. Creates and executes a PHP test script that:
    • Instantiates the JsonSerializer
    • Creates a malicious JSON payload with @type specifying an arbitrary class
    • Calls unserialize() with the malicious payload
    • Verifies that the arbitrary class is instantiated
    • Confirms that __wakeup() is called (demonstrating the danger)
    • Checks for the absence of setAllowedClasses() method

Expected Evidence:

[TEST] Malicious JSON payload: {"@type":"VulnerableTarget","data":"injected"}
[VULNERABILITY CONFIRMED] __wakeup() was called on arbitrary class!
[RESULT] Class instantiated: VulnerableTarget
[RESULT] __wakeup() called: YES
[CHECK] setAllowedClasses() method: MISSING (vulnerable)
=== CONCLUSION ===
VULNERABILITY CONFIRMED: Arbitrary class instantiation works!
Evidence

Log Location: logs/repro_output.log

Key Excerpts:

=== GHSA-v7m3-fpcr-h7m2 Reproduction Script ===
[TEST] Malicious JSON payload: {"@type":"VulnerableTarget","data":"injected"}
[VULNERABILITY CONFIRMED] __wakeup() was called on arbitrary class!
[RESULT] Class instantiated: VulnerableTarget
[RESULT] Data value: injected
[RESULT] __wakeup() called: YES
[CHECK] setAllowedClasses() method: MISSING (vulnerable)
VULNERABILITY CONFIRMED: Arbitrary class instantiation works!

Environment Details:

  • PHP Version: 8.4.18
  • Package: zumba/json-serializer v3.2.2
  • OS: Linux (Debian-based)
Recommendations / Next Steps

Immediate Actions:

  1. Upgrade to version 3.2.3 or later immediately
  2. Configure allowlist: After upgrading, use setAllowedClasses() to restrict which classes may be deserialized:
    $serializer = new JsonSerializer();
    $serializer->setAllowedClasses(['AllowedClass1', 'AllowedClass2']);
    
  3. Audit applications using this library to ensure they don't process untrusted JSON input

Testing Recommendations:

  1. Add unit tests that attempt to instantiate disallowed classes
  2. Implement input validation before passing JSON to the deserializer
  3. Consider using a Web Application Firewall (WAF) rule to detect @type fields in untrusted input
  4. Review dependency tree for exploitable gadget chains (using tools like PHPGGC)

Long-term:

  • Consider using alternative serialization formats with built-in type safety
  • Implement defense-in-depth with additional input validation layers
Additional Notes

Idempotency Confirmation: The reproduction script has been run twice consecutively with identical results:

  • Run 1: Exit code 0 (vulnerability confirmed)
  • Run 2: Exit code 0 (vulnerability confirmed)

Edge Cases:

  • The vulnerability only affects applications that deserialize untrusted JSON input
  • Applications that only deserialize trusted/internal data are not affected
  • The impact depends on available gadget chains in the application or its dependencies

Limitations:

  • This reproduction demonstrates the class instantiation capability but does not demonstrate actual RCE
  • Full RCE would require a suitable gadget chain in the target application dependencies
  • The fix in v3.2.3 is opt-in (requires calling setAllowedClasses()) for backward compatibility

CVE-2026-27206 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:002:33
0:00
session startedaccounts/fireworks/models/kimi-k2p5 · ghsa-v7m3-fpcr-h7m2 · ghsa-v7m
0:07
0:22
0:34
0:37
web search
0:55
0:58
1:07
1:07
extract_facts
no facts extracted
1:12
1:12
1:12
supportrepro
2:10
2:10
2:10
2:11
2:11
2:11
2:24
2:28
web search
2:33

Artifacts and Evidence for CVE-2026-27206

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-27206

Upgrade zumba/json-serializer · composer to 3.2.3 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-27206 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-27206

How does the JSON Serializer object-injection attack work?

An attacker who can pass JSON into JsonSerializer::unserialize() sets @type to the name of an application or dependency class that has dangerous magic methods such as __wakeup() or __destruct(). The library instantiates that class based purely on the attacker-supplied @type value, and if a usable gadget chain exists in the target application, this can escalate to remote code execution, data exfiltration, file manipulation, or denial of service.

Which zumba/json-serializer versions are affected by CVE-2026-27206, and where is it fixed?

Versions < 3.2.3 are affected; it is fixed in 3.2.3.

How severe is CVE-2026-27206?

High (the root-cause analysis cites CVSS 8.1) — exploitation requires untrusted JSON reaching unserialize() plus a usable gadget chain in the application or its dependencies, similar in risk to PHP's native unserialize() without allowed_classes.

How can I reproduce CVE-2026-27206?

Download the verified script from this page and run it in an isolated environment against zumba/json-serializer < 3.2.3. It passes crafted JSON containing an @type field naming a class with a dangerous magic method into JsonSerializer::unserialize() and shows the class being instantiated, then confirms 3.2.3 rejects the unrestricted @type.
11 · References

References for CVE-2026-27206

Authoritative sources for CVE-2026-27206 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.