PHP security explainer · defensive
PHP object injection: what it is and how to fix it
Passing user-controlled data to unserialize() lets an attacker choose which objects PHP creates. The PHP manual warns against exactly that.
Last updated
What it is
When PHP unserializes a string it recreates the objects described in it and may call magic methods such as __wakeup() and __destruct(). If the string comes from a cookie, form field or API request, an attacker can pick classes already loaded by the application or its libraries and chain their methods, which can lead to file writes or code execution. MITRE tracks this as CWE-502, deserialization of untrusted data.
How to detect it
- Search your code for
unserialize(and trace where each argument comes from. Any path from$_GET,$_POST,$_COOKIE, headers, uploaded files or a database field users can write is a finding. - Check third-party plugins and old libraries the same way; many historic CMS plugin advisories were object injection.
- Static analysers such as PHPStan or Psalm with security rules, and dependency audits (
composer audit), help find known vulnerable packages.
How to fix it
- Use
json_encode()andjson_decode()for data that crosses a trust boundary. JSON cannot create PHP objects. - If you must call
unserialize(), pass['allowed_classes' => false]or a short explicit list. The PHP manual still says not to pass untrusted input even then. - Sign serialized data you store client-side with an HMAC and verify it before decoding.
- Keep frameworks and libraries updated so known gadget chains are removed.
Read-only checks and safe patterns
# Find unserialize() calls that may receive request data (read-only)
grep -rnE "unserialize\s*\(" --include=*.php . | grep -vE "/vendor/|/tests?/"
// Safer: exchange data as JSON
$data = json_decode($input, true, 512, JSON_THROW_ON_ERROR);
// If unserialize() is unavoidable for trusted data, forbid objects
$data = unserialize($trusted, ['allowed_classes' => false]);Is allowed_classes => false enough?
It blocks object creation, which removes the main risk, but the PHP manual still advises against unserializing untrusted input. JSON is the safer default.
Does this relate to PHP2Shell?
No. PHP2Shell is a bug in the PHP runtime. Object injection is a bug in application code and exists on fully patched PHP.
Other PHP vulnerability classes
- PHP file inclusion (LFI/RFI): what it is and how to fix itFile inclusion happens when user input controls the path passed to include or require, letting an attacker read local files (LFI) or, with allow_url_include on, run remote code (RFI).
- SSRF in PHP: what it is and how to fix itServer-side request forgery (SSRF) happens when a PHP app fetches a URL the user controls, letting an attacker reach internal services or cloud metadata endpoints through your server.
- XSS in PHP: what it is and how to prevent itCross-site scripting (XSS) happens when a PHP page outputs user-controlled data into HTML without escaping, so an attacker’s script runs in other visitors’ browsers.
- phpinfo() exposure: why it matters and how to fix itA public phpinfo() page reveals the exact PHP version, loaded modules, file paths and often environment variables or secrets, which helps attackers target bugs such as PHP2Shell.
Sources
Outbound links leave this site. We do not host exploit code.
- unserialize() — PHP Manual
- json_decode() — PHP Manual
- PHP Object Injection — OWASP
- CWE-502: Deserialization of Untrusted Data — MITRE CWE