Check Deserialization logo

Check Deserialization

Community
dykyi-roman
check-deserialization

Analyzes PHP code for insecure deserialization. Detects unserialize with user input, missing allowed_classes, PHP object injection risks, gadget chains.

Overview

Publisherdykyi-roman
Repositoryawesome-claude-code
Skill namecheck-deserialization
Stars
98
Forks
25
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by dykyi-roman on GitHub. Read the source before you install it.

Installation

Install the Check Deserialization AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/dykyi-roman/awesome-claude-code.git /tmp/awesome-claude-code
mkdir -p .claude/skills
cp -r /tmp/awesome-claude-code/skills/check-deserialization .claude/skills/check-deserialization
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Check Deserialization in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Check Deserialization on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Check Deserialization is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Insecure Deserialization Security Check

Analyze PHP code for insecure deserialization vulnerabilities (OWASP A08:2021).

Detection Patterns

1. Unserialize with User Input

php
// CRITICAL: Direct user input
$data = unserialize($_GET['data']);
$object = unserialize($_POST['payload']);
$config = unserialize($_COOKIE['session']);

// CRITICAL: Request object
$data = unserialize($request->input('data'));

// CRITICAL: From file upload
$content = file_get_contents($_FILES['import']['tmp_name']);
$data = unserialize($content);

2. Missing allowed_classes Option

php
// CRITICAL: No allowed_classes restriction (PHP 7+)
$data = unserialize($serialized);
// Can instantiate ANY class

// CRITICAL: allowed_classes = true (default behavior)
$data = unserialize($serialized, ['allowed_classes' => true]);

// SECURE: No objects allowed
$data = unserialize($serialized, ['allowed_classes' => false]);

// SECURE: Whitelist specific classes
$data = unserialize($serialized, [
    'allowed_classes' => [User::class, Config::class],
]);

3. Gadget Chain Triggers

php
// VULNERABLE: Classes with dangerous magic methods
class FileHandler
{
    private string $path;

    // Called on unserialize - could delete arbitrary files
    public function __wakeup(): void
    {
        unlink($this->path);
    }
}

class Logger
{
    private string $logFile;
    private string $data;

    // Called when object destroyed - could write arbitrary files
    public function __destruct()
    {
        file_put_contents($this->logFile, $this->data);
    }
}

class DataLoader
{
    private string $source;

    // Called on property access - SSRF/file read
    public function __get($name)
    {
        return file_get_contents($this->source);
    }
}

class CommandRunner
{
    private string $command;

    // Called when object used as string - RCE
    public function __toString(): string
    {
        return shell_exec($this->command);
    }
}

4. Database-Stored Serialized Data

php
// CRITICAL: Trusting database content
$row = $db->query("SELECT settings FROM users WHERE id = ?", [$id]);
$settings = unserialize($row['settings']);
// If attacker can modify DB (SQL injection), they control serialized data

// CRITICAL: Session storage
$sessionData = unserialize($redis->get('session:' . $sessionId));

5. Phar Deserialization

php
// CRITICAL: Phar metadata triggers unserialize
$phar = new Phar($userUploadedFile);
// Reading phar file deserializes metadata

// CRITICAL: File operations on phar://
file_exists('phar://' . $uploadedFile);
file_get_contents('phar://' . $userFile);
is_dir('phar://' . $path);
fopen('phar://' . $filename, 'r');

// CRITICAL: include/require phar
include 'phar://' . $plugin . '/bootstrap.php';

6. Base64-Encoded Serialized Data

php
// CRITICAL: Common pattern to hide serialized data
$payload = base64_decode($_GET['token']);
$data = unserialize($payload);

// CRITICAL: In cookies
$sessionData = unserialize(base64_decode($_COOKIE['session']));

// CRITICAL: In headers
$auth = unserialize(base64_decode($request->header('X-Auth-Data')));

7. JSON with Object Mapping

php
// POTENTIALLY VULNERABLE: JSON to object without validation
$json = file_get_contents('php://input');
$data = json_decode($json);

// CRITICAL: Mapping to class with dangerous methods
$object = (new UserDTO())->fromArray(json_decode($json, true));
// If class has __set or __call that executes code

// CRITICAL: Doctrine/JMS Serializer without type whitelist
$user = $this->serializer->deserialize($json, 'object', 'json');

8. Cache Deserialization

php
// CRITICAL: Cache poisoning leads to object injection
$cacheKey = 'user_' . $userId;
$user = unserialize($cache->get($cacheKey));
// If cache can be poisoned, attacker controls object

// CRITICAL: File-based cache
$cached = file_get_contents("/tmp/cache/{$key}.cache");
$data = unserialize($cached);

9. Framework-Specific Patterns

php
// CRITICAL: Laravel signed URLs without validation
$data = unserialize($request->input('signed_data'));

// CRITICAL: Symfony serialized tokens
$token = unserialize($session->get('_security_main'));

// CRITICAL: Custom session handlers
class MySessionHandler implements SessionHandlerInterface
{
    public function read($id): string|false
    {
        $data = $this->storage->get($id);
        return unserialize($data); // Dangerous
    }
}

10. RPC/IPC Serialization

php
// CRITICAL: Inter-process communication
$message = unserialize(file_get_contents('php://stdin'));

// CRITICAL: Queue messages
$job = unserialize($queue->pop());

// CRITICAL: Socket data
$data = unserialize(socket_read($socket, 1024));

Grep Patterns

bash
# unserialize calls
Grep: "unserialize\s*\(" --glob "**/*.php"

# unserialize with user input
Grep: "unserialize\s*\([^)]*(\\\$_GET|\\\$_POST|\\\$_COOKIE|\\\$_REQUEST)" --glob "**/*.php"

# phar:// usage
Grep: "phar://" --glob "**/*.php"

# Magic methods that could be exploited
Grep: "__wakeup|__destruct|__toString|__call\s*\(" --glob "**/*.php"

# Missing allowed_classes
Grep: "unserialize\s*\([^)]+\)\s*;" --glob "**/*.php"

Secure Patterns

Use JSON Instead

php
// SECURE: JSON for data interchange
$data = json_decode($input, true, 512, JSON_THROW_ON_ERROR);

// SECURE: Validate JSON structure
$data = json_decode($input, true);
if (!isset($data['expected_field'])) {
    throw new InvalidInputException();
}

Restrict allowed_classes

php
// SECURE: Only allow specific classes
$allowed = [
    UserDTO::class,
    ConfigDTO::class,
];

$data = unserialize($serialized, ['allowed_classes' => $allowed]);

// SECURE: No objects at all (for arrays/primitives)
$data = unserialize($serialized, ['allowed_classes' => false]);

Signature Verification

php
// SECURE: Sign serialized data
final class SecureSerializer
{
    public function __construct(
        private readonly string $secretKey,
    ) {}

    public function serialize(mixed $data): string
    {
        $serialized = serialize($data);
        $signature = hash_hmac('sha256', $serialized, $this->secretKey);
        return base64_encode($signature . $serialized);
    }

    public function unserialize(string $input, array $allowedClasses = []): mixed
    {
        $decoded = base64_decode($input, true);
        if ($decoded === false || strlen($decoded) < 64) {
            throw new SecurityException('Invalid data format');
        }

        $signature = substr($decoded, 0, 64);
        $serialized = substr($decoded, 64);

        $expected = hash_hmac('sha256', $serialized, $this->secretKey);
        if (!hash_equals($expected, $signature)) {
            throw new SecurityException('Invalid signature');
        }

        return unserialize($serialized, ['allowed_classes' => $allowedClasses]);
    }
}

Use Typed DTOs

php
// SECURE: Manual mapping to DTO
final readonly class CreateUserRequest
{
    public function __construct(
        public string $name,
        public string $email,
        public int $age,
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            name: $data['name'] ?? throw new ValidationException('Name required'),
            email: $data['email'] ?? throw new ValidationException('Email required'),
            age: (int) ($data['age'] ?? throw new ValidationException('Age required')),
        );
    }
}

// Usage
$data = json_decode($input, true);
$request = CreateUserRequest::fromArray($data);

Disable Phar Wrapper

php
// In php.ini
; phar.readonly = 1  (prevents phar creation)

// At runtime - remove phar wrapper
stream_wrapper_unregister('phar');

// Validate file type before operations
if (pathinfo($file, PATHINFO_EXTENSION) === 'phar') {
    throw new SecurityException('Phar files not allowed');
}

Severity Classification

PatternSeverityCWE
unserialize($_GET/$_POST)🔴 CriticalCWE-502
unserialize without allowed_classes🔴 CriticalCWE-502
Phar with user-controlled path🔴 CriticalCWE-502
Classes with dangerous __destruct🟠 MajorCWE-502
Cache/DB deserialization🟠 MajorCWE-502
Missing signature verification🟡 MinorCWE-502

Output Format

markdown
### Insecure Deserialization: [Description]

**Severity:** 🔴 Critical
**Location:** `file.php:line`
**CWE:** CWE-502 (Deserialization of Untrusted Data)

**Issue:**
User-controlled data is deserialized without restrictions, allowing object injection.

**Attack Vector:**
1. Attacker crafts serialized payload with gadget chain
2. Payload triggers __destruct() that writes to file
3. Attacker achieves remote code execution

**Code:**
```php
// Vulnerable
$data = unserialize($_POST['data']);

Fix:

php
// Secure: Use JSON or restrict classes
$data = json_decode($_POST['data'], true);

// Or with signature and whitelist
$data = unserialize($payload, [
    'allowed_classes' => [SafeDTO::class],
]);

References:

Frequently asked questions

What does the Check Deserialization AI skill do?

Analyzes PHP code for insecure deserialization. Detects unserialize with user input, missing allowed_classes, PHP object injection risks, gadget chains.

Why use Check Deserialization on TypingMind?

Because you install it once and use it with any model. Check Deserialization is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Check Deserialization in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/dykyi-roman/awesome-claude-code/tree/master/skills/check-deserialization. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Check Deserialization?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Check Deserialization?

As many as you like. As long as a model supports skills, you can use Check Deserialization with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Check Deserialization AI skill free?

Yes. It is published on GitHub by dykyi-roman under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇