Stop PHP Object Injection: Priority Fixes for Secure Code
Disabling deserialization entirely eliminates the threat, while input validation alone fails because attackers bypass filters using encoded payloads that look harmless to basic checks.

Prevent PHP object injection by disabling the magic method `__wakeup()` and avoiding `unserialize()` on user input. Replace object serialization with JSON or structured data formats. Validate all incoming data types strictly. Use allowlists for expected data structures. Never trust external sources with serialized objects, as this bypasses standard security controls and leads to remote code execution.
The Mechanics of Object Injection
PHP object injection occurs when an application deserializes untrusted data. Deserialization converts a string back into a PHP object. The language restores the object’s state, including its properties and methods. If an attacker controls the serialized string, they can craft a payload that instantiates a specific class. This class may contain dangerous methods, such as file operations or database queries.
The application executes these methods automatically during the restoration process. This happens before any business logic validation. The attacker does not need to guess the class name. They can often find vulnerable classes in the application’s own library. This turns a data parsing function into a code execution engine.

Why Input Validation Fails
Many developers assume that filtering input stops object injection. This assumption is incorrect. Attackers encode their payloads using various techniques. Base64 encoding, URL encoding, and hex encoding all transform the malicious string. Standard filters often miss these encoded variants. The filter sees safe characters. The deserializer decodes the string and reveals the dangerous object. Validation checks the surface, not the structure. You cannot validate the intent of a serialized blob. The data looks like random noise to a simple filter. This is why validation is a weak defense. It provides a false sense of security. The underlying mechanism remains open to exploitation.
Priority One: Disable Deserialization
The most effective measure is to stop deserializing untrusted data. If your application does not need to restore complex PHP objects from user input, disable the feature. Remove calls to unserialize() for any data originating outside the application. This includes cookies, query parameters, and POST bodies. If you must handle external data, use a different format. JSON and XML are safer because they do not instantiate classes. They parse into simple arrays or objects. You control the structure of the data. You define how the data is used. This removes the ability for an attacker to trigger arbitrary code execution. It is a binary choice. Either you trust the source completely, or you do not deserialize.
Priority Two: Enforce Type Constraints
If you cannot disable deserialization, enforce strict type constraints. PHP allows you to specify which classes can be instantiated. Use the allowed_classes option in unserialize(). This option restricts the deserializer to a whitelist of safe classes. Any attempt to instantiate a class not on the list fails. This prevents the use of dangerous system classes. It limits the damage to the specific classes you permit. You must audit these classes carefully. Even a safe class can be dangerous if it has a magic method. Check for __wakeup(), __destruct(), and __toString(). These methods run automatically. They can execute code even if the class itself seems benign.
Priority Three: Validate Magic Methods
Magic methods are special functions in PHP that trigger on specific events. __wakeup() runs when an object is unserialized. __destruct() runs when the object is destroyed. __toString() runs when the object is cast to a string. Attackers chain these methods together. This is called a gadget chain. One method calls another, eventually reaching a dangerous function. You must audit every class in your application. Identify all magic methods. Determine if they perform sensitive actions. If a magic method interacts with the file system or database, it is a risk. Consider removing or rewriting these methods. If they are necessary, ensure they validate their own inputs. This reduces the surface area for gadget chains.
| Measure | Effort | What it stops |
|---|---|---|
Disable unserialize() | Low | All object injection via that function |
Use allowed_classes | Medium | Instantiation of unauthorized classes |
| Audit magic methods | High | Gadget chains within allowed classes |
| Input filtering | Low | Nothing reliable; easily bypassed |
Replacing Serialization with Safer Formats
Consider replacing PHP serialization with data interchange formats. JSON is a common alternative. It stores data as key-value pairs. It does not store class information. When you parse JSON, you get an array or a standard object. You must explicitly create the PHP objects from this data. This gives you control over the instantiation process.
You can validate the data before creating the object. XML is another option. It is more verbose but also safe from object injection. These formats are widely supported. They work across different languages and platforms. This improves interoperability. It also removes the dependency on PHP-specific serialization. This is a long-term architectural improvement.
The Hidden Cost of Legacy Code
Legacy applications often rely on object serialization for session storage. Sessions store user state between requests. PHP serializes the session data by default. If an attacker can modify the session cookie, they can inject objects. This is a common attack vector. You must configure PHP to use a safe session handler. JSON or custom handlers are safer. You also need to secure the session cookie. Use the httponly and secure flags. This prevents JavaScript access and ensures HTTPS transmission. Do not store sensitive data in sessions. Keep sessions minimal. This reduces the impact if a session is compromised. Review your session configuration regularly. Ensure it aligns with current security standards.
What Does Not Work
Several common measures do not stop object injection. Escaping output prevents cross-site scripting (XSS). It does not stop deserialization. Input validation, as noted, is easily bypassed. Using a web application firewall (WAF) can help. WAFs detect known patterns. They are not a complete solution. Attackers create new payloads. A WAF may miss them. Do not rely on a WAF as your primary defense. It is a layer of defense in depth. It complements code fixes. It does not replace them. You must fix the code. You must remove the vulnerability. Relying on external tools leaves you exposed to novel attacks.
Closing Checklist for Immediate Action
Review your codebase for unserialize() calls. Identify where user input reaches this function. Disable deserialization for any external data source. Configure allowed_classes if you must deserialize. Audit your classes for dangerous magic methods. Replace session serialization with a safer format. These steps reduce your risk significantly. They address the root cause. They do not rely on filtering. They enforce structural safety. Implement these changes today. Schedule a review for your dependency updates. Ensure your libraries are secure. Check for related issues like command injection. Secure your entire application stack. This proactive approach protects your business.
Key takeaways
- Disabling `unserialize()` on external input removes the primary attack vector for object injection vulnerabilities.
- Input validation fails when attackers encode malicious payloads, making type enforcement and allowlists necessary defenses.
- Replacing object serialization with JSON or XML structures prevents the instantiation of arbitrary classes during data parsing.
Disabling deserialization on untrusted input is the only reliable way to prevent PHP object injection. Audit your code for `unserialize()` calls and replace them with JSON parsing or strict type constraints today.
Frequently asked questions
Does HTTPS prevent PHP object injection?
No, HTTPS encrypts data in transit but does not validate the content. An attacker can send a malicious serialized payload over an encrypted connection, and the server will still process it if the code is vulnerable.
Can I use input sanitization to stop object injection?
Input sanitization is unreliable for this threat. Attackers use encoding techniques to bypass filters, making sanitization ineffective as a standalone defense against crafted serialized payloads.
How do I know if my session data is vulnerable?
If your application uses PHP’s default session handler and stores objects in the session, it is vulnerable. Attackers can manipulate session cookies to inject malicious objects during deserialization.
Is JSON completely safe from injection?
JSON parsing is safe from object injection because it does not instantiate classes. However, you must still validate the parsed data to prevent other issues like cross-site scripting or command injection.
How this guide was produced: written by the Shell Bulletin editorial team with AI assistance, checked against the public references listed below, and reviewed when the facts change. See our editorial policy or report an error.



