Executive Summary
CVE-2026-14637 is a high-severity PHP deserialization vulnerability in kirilkirkov/Ecommerce-CodeIgniter-Bootstrap. The getCartItems() function in application/libraries/ShoppingCart.php passes the shopping_cart cookie value directly to PHP's unserialize() without sanitization, enabling PHP Object Injection attacks that can escalate to full Remote Code Execution through a crafted gadget chain.
CVSS Score: 8.2 (High)
This class of vulnerability is particularly dangerous because exploitation requires no special privileges — any visitor with a browser can craft the malicious cookie and deliver it.
Vulnerability Overview
Root Cause
The getCartItems() function in the shopping cart library reads the shopping_cart cookie and deserializes it with no input validation:
// Vulnerable pattern (simplified)
public function getCartItems() {
$cart_data = $this->input->cookie('shopping_cart');
return unserialize($cart_data); // DANGEROUS: user-controlled input
}When PHP deserializes an attacker-supplied object, it automatically calls magic methods (__wakeup, __destruct, __toString) on the constructed object. If the application's codebase contains usable "gadget" classes — objects whose magic methods perform dangerous operations — the attacker can chain them to execute arbitrary commands.
Attack Surface
| Component | Detail |
|---|---|
| Entry Point | shopping_cart HTTP cookie |
| Auth Required | None — any unauthenticated visitor |
| Mechanism | PHP unserialize() on attacker-controlled data |
| Impact | RCE, file write, credential theft, denial of service |
| CVSS | 8.2 (High) — network accessible, no privileges required |
Attack Chain
1. Attacker identifies target running vulnerable ecommerce framework
2. Scans codebase for usable PHP gadget chains (__destruct, __wakeup, etc.)
3. Crafts serialized PHP object payload encoding the gadget chain
4. Sends crafted payload as shopping_cart cookie in HTTP request
5. Server calls unserialize() — PHP constructs attacker's objects
6. Magic method fires, executes arbitrary OS command
7. Attacker achieves full remote code executionTechnical Details
PHP Object Injection Mechanics
PHP deserialization is fundamentally different from parsing JSON or XML — it reconstructs actual PHP objects, including calling their lifecycle hooks. An attacker who can control the input to unserialize() can:
- Instantiate any class available in the application's autoloader
- Trigger
__wakeup()on deserialization - Trigger
__destruct()when the object goes out of scope - Chain multiple objects via property references
Example Gadget Pattern (Generic)
class FileWriter {
public $filename;
public $content;
public function __destruct() {
// This fires automatically when object is destroyed
file_put_contents($this->filename, $this->content);
}
}
// Attacker serializes:
$exploit = new FileWriter();
$exploit->filename = '/var/www/html/shell.php';
$exploit->content = '<?php system($_GET["cmd"]); ?>';
echo serialize($exploit);
// Output: O:10:"FileWriter":2:{s:8:"filename";s:30:...}PHPGGC — Automated Gadget Chain Generation
Tools like PHPGGC automate gadget chain discovery for popular PHP frameworks including CodeIgniter. An attacker can generate a working payload in seconds:
phpggc CodeIgniter/RCE1 system idAffected Versions
| Commit | Status |
|---|---|
Up to 13fd582aaf49aeab7438acc0fc3eb973a1f5e6a7 | Vulnerable |
| No CVE-specific patch published at time of disclosure | Check upstream |
Remediation
Fix: Replace unserialize() with json_decode()
The safest remediation is to stop using PHP serialization for cookie storage entirely:
// SECURE: Use JSON instead of PHP serialization
public function getCartItems() {
$cart_data = $this->input->cookie('shopping_cart');
// json_decode does not instantiate PHP objects
return json_decode($cart_data, true) ?? [];
}
public function saveCartItems($items) {
$this->input->set_cookie('shopping_cart', json_encode($items), 86400);
}If PHP Serialization Must Be Retained
Use unserialize() with an explicit allowlist of permitted classes:
// Restrict deserialization to known-safe classes only
$allowed_classes = ['CartItem', 'ProductRef'];
$cart = unserialize($cart_data, ['allowed_classes' => $allowed_classes]);Additional Hardening
- Digitally sign cookie values (HMAC-SHA256) to prevent tampering
- Store cart data server-side (session or database) — never trust client-side serialized state
- Audit all
unserialize()calls in the codebase for user-controlled input
Detection
Identify unserialize() Usage in Codebase
grep -rn "unserialize(" application/ --include="*.php"Monitor for Deserialization Attack Patterns in Logs
# Look for serialized object patterns in cookie headers
grep -E 'shopping_cart=O:[0-9]' /var/log/apache2/access.logWAF Rule (ModSecurity)
SecRule REQUEST_COOKIES:shopping_cart "@rx O:[0-9]+:\"" \
"id:2026146370,phase:1,deny,status:400,\
msg:'CVE-2026-14637 PHP Object Injection Attempt'"
References
- NVD — CVE-2026-14637
- OWASP — PHP Object Injection
- PHPGGC — PHP Generic Gadget Chains
- kirilkirkov/Ecommerce-CodeIgniter-Bootstrap