Matter AI | Code Reviewer Documentation home pagelight logodark logo
  • Contact
  • Github
  • Sign in
  • Sign in
  • Documentation
  • Blog
  • Discord
  • Github
  • Introduction
    • What is Matter AI?
    Getting Started
    • QuickStart
    Product
    • Security Analysis
    • Code Quality
    • Agentic Chat
    • RuleSets
    • Memories
    • Analytics
    • Command List
    • Configurations
    Patterns
    • Languages
    • Security
      • Injection Vulnerabilities
      • Authentication Vulnerabilities
      • Authorization Vulnerabilities
      • Cryptography Vulnerabilities
      • Data Protection Vulnerabilities
      • Input Validation Vulnerabilities
      • Session Management Vulnerabilities
      • Error Handling Vulnerabilities
      • Logging Vulnerabilities
      • Configuration Vulnerabilities
      • File Handling Vulnerabilities
      • Memory Management Vulnerabilities
      • API Security Vulnerabilities
      • Cross-Site Scripting Vulnerabilities
      • Cross-Site Request Forgery Vulnerabilities
      • Insecure Deserialization Vulnerabilities
      • Security Misconfiguration Vulnerabilities
      • Broken Access Control Vulnerabilities
      • Sensitive Data Exposure Vulnerabilities
      • XML Vulnerabilities
      • Regular Expression Denial of Service (ReDoS)
    • Performance
    Integrations
    • Code Repositories
    • Team Messengers
    • Ticketing
    Enterprise
    • Enterprise Deployment Overview
    • Enterprise Configurations
    • Observability and Fallbacks
    • Create Your Own GitHub App
    • Self-Hosting Options
    • RBAC
    Patterns
    Security

    Insecure Deserialization Vulnerabilities

    Insecure deserialization vulnerabilities occur when applications deserialize untrusted data without proper validation, potentially leading to remote code execution, denial of service, or privilege escalation.

    Insecure deserialization vulnerabilities occur when applications deserialize untrusted data without proper validation or protection. Serialization is the process of converting complex data structures into a format that can be stored or transmitted, while deserialization is the reverse process of reconstructing these data structures.

    When an application deserializes untrusted data, attackers can manipulate the serialized data to achieve various attacks, including remote code execution, denial of service, authentication bypass, or privilege escalation.

    Preventing insecure deserialization requires implementing proper input validation, using secure deserialization libraries, and adopting safer alternatives to native serialization mechanisms.

    // Anti-pattern: Unsafe Java deserialization
    import java.io.ObjectInputStream;
    import java.io.ByteArrayInputStream;
    import java.util.Base64;
    
    public class UserManager {
        public User loadUserFromToken(String token) {
            try {
                // Decode the base64 token
                byte[] serializedData = Base64.getDecoder().decode(token);
                
                // Deserialize without any validation
                ObjectInputStream ois = new ObjectInputStream(
                    new ByteArrayInputStream(serializedData));
                
                // Unsafe deserialization of untrusted data
                return (User) ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
    // Better approach: Using a safer alternative
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class UserManager {
        private final ObjectMapper objectMapper = new ObjectMapper();
        
        public User loadUserFromToken(String token) {
            try {
                // Decode the base64 token
                byte[] data = Base64.getDecoder().decode(token);
                String json = new String(data, "UTF-8");
                
                // Use JSON deserialization instead of native Java serialization
                return objectMapper.readValue(json, User.class);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
    // Even better: Using a whitelist approach with Jackson
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.json.JsonMapper;
    import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
    
    public class UserManager {
        private final ObjectMapper objectMapper;
        
        public UserManager() {
            // Configure Jackson with a whitelist of allowed classes
            BasicPolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
                .allowIfBaseType(User.class)
                .allowIfSubType("com.example.model.")
                .build();
            
            objectMapper = JsonMapper.builder()
                .activateDefaultTyping(validator, ObjectMapper.DefaultTyping.NON_FINAL)
                .build();
        }
        
        public User loadUserFromToken(String token) {
            try {
                byte[] data = Base64.getDecoder().decode(token);
                String json = new String(data, "UTF-8");
                
                return objectMapper.readValue(json, User.class);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    Java’s native serialization mechanism is particularly vulnerable to deserialization attacks, as it allows for arbitrary code execution during the deserialization process.

    To prevent unsafe Java deserialization:

    • Avoid using Java’s native serialization (ObjectInputStream) for untrusted data
    • Use safer alternatives like JSON, XML, or YAML with appropriate libraries
    • If native serialization is necessary, implement a whitelist of allowed classes
    • Consider using serialization filtering in Java 9+ (ObjectInputFilter)
    • Keep all libraries and dependencies updated
    • Implement proper exception handling
    • Consider using the OWASP SerialKiller or other serialization security libraries
    // Anti-pattern: Unsafe PHP deserialization
    <?php
    // User data stored in a cookie
    $userData = $_COOKIE['user_data'];
    
    // Unsafe deserialization of untrusted data
    $user = unserialize($userData);
    
    if ($user->isAdmin) {
        // Grant admin access
        showAdminPanel();
    }
    ?>
    
    // Better approach: Using safer alternatives
    <?php
    // Option 1: Using JSON instead of PHP serialization
    $userData = $_COOKIE['user_data'];
    
    // JSON decode with assoc=true to get an array instead of objects
    $userData = json_decode($userData, true);
    
    // Validate the data structure
    if (!isset($userData['username']) || !isset($userData['role'])) {
        die('Invalid user data');
    }
    
    // Use the data safely
    if ($userData['role'] === 'admin') {
        // Verify admin status from database, not just from the cookie
        if (verifyAdminStatus($userData['username'])) {
            showAdminPanel();
        }
    }
    
    // Option 2: If serialization is necessary, use a whitelist approach
    function safeUnserialize($serialized) {
        // Define allowed classes
        $allowedClasses = ['UserData', 'UserPreferences'];
        
        // Set up a whitelist for allowed classes
        $options = ['allowed_classes' => $allowedClasses];
        
        // Unserialize with options (PHP 7+)
        return unserialize($serialized, $options);
    }
    
    $userData = $_COOKIE['user_data'];
    $user = safeUnserialize($userData);
    ?>

    PHP’s unserialize() function can lead to object injection vulnerabilities if used with untrusted data, potentially allowing attackers to instantiate arbitrary classes and trigger unexpected code execution.

    To prevent unsafe PHP deserialization:

    • Avoid using unserialize() with untrusted data
    • Use JSON or other safer formats instead
    • If serialization is necessary, use the allowed_classes option in PHP 7+
    • Implement proper input validation
    • Consider using cryptographic signatures to verify serialized data integrity
    • Keep PHP and all libraries updated
    • Implement proper exception handling
    # Anti-pattern: Unsafe Python deserialization
    import pickle
    import base64
    
    def load_user_preferences(token):
        # Decode the base64 token
        serialized_data = base64.b64decode(token)
        
        # Unsafe deserialization of untrusted data
        user_prefs = pickle.loads(serialized_data)
        
        return user_prefs
    
    # Better approach: Using safer alternatives
    import json
    import base64
    
    def load_user_preferences(token):
        try:
            # Decode the base64 token
            data = base64.b64decode(token)
            
            # Use JSON instead of pickle
            user_prefs = json.loads(data.decode('utf-8'))
            
            # Validate the structure
            if not isinstance(user_prefs, dict):
                raise ValueError("Invalid user preferences format")
            
            # Additional validation of expected fields
            required_fields = ['theme', 'language', 'notifications']
            for field in required_fields:
                if field not in user_prefs:
                    raise ValueError(f"Missing required field: {field}")
            
            return user_prefs
        except Exception as e:
            # Log the error
            print(f"Error loading user preferences: {e}")
            # Return default preferences
            return {'theme': 'default', 'language': 'en', 'notifications': True}
    
    # If complex objects are needed, use a safer serialization library
    import marshmallow
    
    class UserPreferencesSchema(marshmallow.Schema):
        theme = marshmallow.fields.String(required=True)
        language = marshmallow.fields.String(required=True)
        notifications = marshmallow.fields.Boolean(required=True)
    
    def load_user_preferences_with_schema(token):
        try:
            data = base64.b64decode(token)
            json_data = json.loads(data.decode('utf-8'))
            
            # Use schema to validate and deserialize
            schema = UserPreferencesSchema()
            user_prefs = schema.load(json_data)
            
            return user_prefs
        except Exception as e:
            print(f"Error loading user preferences: {e}")
            return {'theme': 'default', 'language': 'en', 'notifications': True}

    Python’s pickle module is notoriously dangerous for deserializing untrusted data, as it can execute arbitrary code during deserialization.

    To prevent unsafe Python deserialization:

    • Never use pickle, marshal, or shelve modules with untrusted data
    • Use safer alternatives like JSON, YAML, or MessagePack
    • Implement proper input validation
    • Consider using schema validation libraries like marshmallow or pydantic
    • If complex object serialization is needed, consider libraries like jsonpickle with safe_mode enabled
    • Implement proper exception handling
    • Keep all dependencies updated
    // Anti-pattern: Unsafe Node.js deserialization
    const serialize = require('node-serialize');
    
    function getUserData(userToken) {
      // Decode the base64 token
      const serializedData = Buffer.from(userToken, 'base64').toString();
      
      // Unsafe deserialization of untrusted data
      return serialize.unserialize(serializedData);
    }
    
    // Better approach: Using safer alternatives
    function getUserData(userToken) {
      try {
        // Decode the base64 token
        const data = Buffer.from(userToken, 'base64').toString();
        
        // Use JSON.parse instead of node-serialize
        const userData = JSON.parse(data);
        
        // Validate the structure
        if (!userData || typeof userData !== 'object') {
          throw new Error('Invalid user data format');
        }
        
        // Additional validation of expected fields
        const requiredFields = ['id', 'username', 'role'];
        for (const field of requiredFields) {
          if (!(field in userData)) {
            throw new Error(`Missing required field: ${field}`);
          }
        }
        
        return userData;
      } catch (error) {
        console.error('Error parsing user data:', error);
        return null;
      }
    }
    
    // If complex objects are needed, use a schema validation library
    const Joi = require('joi');
    
    function getUserDataWithSchema(userToken) {
      try {
        const data = Buffer.from(userToken, 'base64').toString();
        const userData = JSON.parse(data);
        
        // Define a schema for validation
        const userSchema = Joi.object({
          id: Joi.string().required(),
          username: Joi.string().alphanum().min(3).max(30).required(),
          role: Joi.string().valid('user', 'admin', 'moderator').required(),
          preferences: Joi.object({
            theme: Joi.string().valid('light', 'dark', 'system').default('system'),
            notifications: Joi.boolean().default(true)
          }).default()
        });
        
        // Validate against the schema
        const { error, value } = userSchema.validate(userData);
        
        if (error) {
          throw error;
        }
        
        return value;
      } catch (error) {
        console.error('Error parsing user data:', error);
        return null;
      }
    }

    Node.js applications can be vulnerable to deserialization attacks, particularly when using libraries like node-serialize that support serializing functions.

    To prevent unsafe Node.js deserialization:

    • Avoid using libraries that support serializing functions (like node-serialize)
    • Use JSON.parse for deserialization of untrusted data
    • Implement proper input validation
    • Consider using schema validation libraries like Joi or Yup
    • Implement proper error handling
    • Keep all dependencies updated
    • Consider using Object.freeze() to prevent modification of deserialized objects
    // Anti-pattern: Unsafe deserialization in API
    const express = require('express');
    const app = express();
    const serialize = require('node-serialize');
    
    app.use(express.text());
    
    app.post('/api/process-data', (req, res) => {
      try {
        // Deserialize data from request body
        const data = serialize.unserialize(req.body);
        
        // Process the data
        processData(data);
        
        res.json({ success: true });
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });
    
    // Better approach: Safe API deserialization
    const express = require('express');
    const app = express();
    const Joi = require('joi');
    
    // Use JSON middleware instead of text
    app.use(express.json());
    
    // Define a schema for validation
    const dataSchema = Joi.object({
      id: Joi.string().required(),
      name: Joi.string().required(),
      values: Joi.array().items(Joi.number()).required(),
      metadata: Joi.object().pattern(Joi.string(), Joi.string()).optional()
    });
    
    app.post('/api/process-data', (req, res) => {
      try {
        // Validate request body against schema
        const { error, value } = dataSchema.validate(req.body);
        
        if (error) {
          return res.status(400).json({ error: error.message });
        }
        
        // Process the validated data
        processData(value);
        
        res.json({ success: true });
      } catch (error) {
        console.error('Error processing data:', error);
        res.status(500).json({ error: 'Internal server error' });
      }
    });

    APIs that accept serialized data from clients are particularly vulnerable to deserialization attacks, as they often process untrusted data from various sources.

    To prevent deserialization vulnerabilities in APIs:

    • Use safe formats like JSON for data exchange
    • Implement proper input validation and schema validation
    • Set strict content type requirements
    • Implement proper error handling without exposing sensitive details
    • Use rate limiting to prevent DoS attacks via deserialization
    • Implement proper logging and monitoring
    • Keep all dependencies updated
    • Consider implementing API gateways with additional security controls
    // Anti-pattern: Vulnerable to gadget chain attacks
    import java.io.ObjectInputStream;
    import java.io.ByteArrayInputStream;
    import java.util.Base64;
    
    public class DataProcessor {
        public void processData(String serializedData) {
            try {
                byte[] data = Base64.getDecoder().decode(serializedData);
                
                // Vulnerable to gadget chain attacks
                ObjectInputStream ois = new ObjectInputStream(
                    new ByteArrayInputStream(data));
                
                Object obj = ois.readObject();
                processObject(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        private void processObject(Object obj) {
            // Process the deserialized object
        }
    }
    
    // Better approach: Using serialization filters
    import java.io.ObjectInputStream;
    import java.io.ByteArrayInputStream;
    import java.io.InvalidClassException;
    import java.util.Base64;
    import java.io.ObjectInputFilter;
    
    public class DataProcessor {
        public void processData(String serializedData) {
            try {
                byte[] data = Base64.getDecoder().decode(serializedData);
                
                ByteArrayInputStream bais = new ByteArrayInputStream(data);
                ObjectInputStream ois = new ObjectInputStream(bais);
                
                // Set up serialization filter (Java 9+)
                ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
                    "com.example.model.*;java.util.ArrayList;java.util.HashMap");
                
                ois.setObjectInputFilter(filter);
                
                Object obj = ois.readObject();
                processObject(obj);
            } catch (InvalidClassException ice) {
                System.err.println("Security violation: " + ice.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        private void processObject(Object obj) {
            // Process the deserialized object
        }
    }

    Gadget chains are a particularly dangerous aspect of deserialization vulnerabilities, where attackers chain together multiple classes to achieve malicious outcomes during deserialization.

    To prevent gadget chain attacks:

    • Avoid using native serialization mechanisms with untrusted data
    • Implement class whitelisting for deserialization
    • Use serialization filters (e.g., ObjectInputFilter in Java 9+)
    • Keep all libraries and dependencies updated
    • Consider using deserialization security libraries
    • Implement proper exception handling
    • Consider using runtime application self-protection (RASP) solutions
    // Anti-pattern: Vulnerable to DoS via deserialization
    import java.io.ObjectInputStream;
    import java.io.ByteArrayInputStream;
    
    public class MessageProcessor {
        public void processMessage(byte[] serializedData) {
            try {
                // No size limits or timeouts
                ObjectInputStream ois = new ObjectInputStream(
                    new ByteArrayInputStream(serializedData));
                
                Object message = ois.readObject();
                handleMessage(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        private void handleMessage(Object message) {
            // Process the message
        }
    }
    
    // Better approach: Implementing protections against DoS
    import java.io.ObjectInputStream;
    import java.io.ByteArrayInputStream;
    import java.util.concurrent.*;
    
    public class MessageProcessor {
        private static final int MAX_DATA_SIZE = 1024 * 1024; // 1MB
        private static final int DESERIALIZATION_TIMEOUT = 5; // 5 seconds
        
        public void processMessage(byte[] serializedData) {
            // Check data size
            if (serializedData.length > MAX_DATA_SIZE) {
                System.err.println("Data too large: " + serializedData.length + " bytes");
                return;
            }
            
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<Object> future = executor.submit(() -> {
                try {
                    ObjectInputStream ois = new ObjectInputStream(
                        new ByteArrayInputStream(serializedData));
                    
                    // Set up serialization filter
                    ois.setObjectInputFilter(createSerializationFilter());
                    
                    return ois.readObject();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            
            try {
                // Apply timeout to deserialization
                Object message = future.get(DESERIALIZATION_TIMEOUT, TimeUnit.SECONDS);
                handleMessage(message);
            } catch (TimeoutException e) {
                System.err.println("Deserialization timed out");
                future.cancel(true);
            } catch (Exception e) {
                System.err.println("Error during deserialization: " + e.getMessage());
            } finally {
                executor.shutdownNow();
            }
        }
        
        private java.io.ObjectInputFilter createSerializationFilter() {
            return java.io.ObjectInputFilter.Config.createFilter(
                "com.example.model.*;java.util.ArrayList;!*");
        }
        
        private void handleMessage(Object message) {
            // Process the message
        }
    }

    Deserialization can be exploited for denial of service attacks by crafting serialized data that consumes excessive resources during deserialization.

    To prevent deserialization denial of service:

    • Implement size limits for serialized data
    • Use timeouts for deserialization operations
    • Implement resource limits (memory, CPU)
    • Consider processing deserialization in a separate process or container
    • Implement proper monitoring and alerting
    • Use rate limiting for endpoints that accept serialized data
    • Consider using more efficient serialization formats
    • Implement circuit breakers for critical systems
    // Pattern 1: Data Transfer Objects with manual deserialization
    public class UserDTO {
        private String username;
        private String email;
        private String role;
        
        // Getters and setters
        
        // Factory method for safe deserialization
        public static UserDTO fromJson(String json) {
            try {
                // Use a JSON library
                ObjectMapper mapper = new ObjectMapper();
                JsonNode node = mapper.readTree(json);
                
                UserDTO dto = new UserDTO();
                
                // Manual extraction and validation
                if (node.has("username") && node.get("username").isTextual()) {
                    dto.setUsername(node.get("username").asText());
                } else {
                    throw new IllegalArgumentException("Invalid or missing username");
                }
                
                if (node.has("email") && node.get("email").isTextual()) {
                    String email = node.get("email").asText();
                    if (!isValidEmail(email)) {
                        throw new IllegalArgumentException("Invalid email format");
                    }
                    dto.setEmail(email);
                } else {
                    throw new IllegalArgumentException("Invalid or missing email");
                }
                
                if (node.has("role") && node.get("role").isTextual()) {
                    String role = node.get("role").asText();
                    if (!isValidRole(role)) {
                        throw new IllegalArgumentException("Invalid role");
                    }
                    dto.setRole(role);
                } else {
                    // Default role if not specified
                    dto.setRole("user");
                }
                
                return dto;
            } catch (Exception e) {
                throw new IllegalArgumentException("Error deserializing user data", e);
            }
        }
        
        private static boolean isValidEmail(String email) {
            // Email validation logic
            return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
        }
        
        private static boolean isValidRole(String role) {
            // Role validation logic
            return Arrays.asList("user", "admin", "moderator").contains(role);
        }
    }
    
    // Pattern 2: Builder pattern with validation
    public class User {
        private final String username;
        private final String email;
        private final String role;
        
        private User(Builder builder) {
            this.username = builder.username;
            this.email = builder.email;
            this.role = builder.role;
        }
        
        // Getters only, no setters for immutability
        
        public static class Builder {
            private String username;
            private String email;
            private String role = "user"; // Default value
            
            public Builder username(String username) {
                this.username = username;
                return this;
            }
            
            public Builder email(String email) {
                this.email = email;
                return this;
            }
            
            public Builder role(String role) {
                this.role = role;
                return this;
            }
            
            public User build() {
                // Validate before creating object
                if (username == null || username.isEmpty()) {
                    throw new IllegalArgumentException("Username cannot be empty");
                }
                
                if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
                    throw new IllegalArgumentException("Invalid email format");
                }
                
                if (!Arrays.asList("user", "admin", "moderator").contains(role)) {
                    throw new IllegalArgumentException("Invalid role");
                }
                
                return new User(this);
            }
        }
        
        // Factory method for JSON deserialization
        public static User fromJson(String json) {
            try {
                ObjectMapper mapper = new ObjectMapper();
                JsonNode node = mapper.readTree(json);
                
                Builder builder = new Builder();
                
                if (node.has("username")) {
                    builder.username(node.get("username").asText());
                }
                
                if (node.has("email")) {
                    builder.email(node.get("email").asText());
                }
                
                if (node.has("role")) {
                    builder.role(node.get("role").asText());
                }
                
                // Validation happens in build()
                return builder.build();
            } catch (Exception e) {
                throw new IllegalArgumentException("Error deserializing user data", e);
            }
        }
    }

    Implementing secure deserialization patterns can help mitigate the risks associated with deserializing untrusted data.

    Key secure deserialization patterns:

    • Use Data Transfer Objects (DTOs) with manual deserialization
    • Implement the Builder pattern with validation
    • Use immutable objects to prevent post-deserialization manipulation
    • Implement factory methods for controlled object creation
    • Use schema validation libraries
    • Implement proper input validation
    • Consider using safer serialization formats
    • Implement proper exception handling
    Insecure Deserialization Prevention Checklist:
    
    1. Avoid Native Serialization
       - Avoid using native serialization mechanisms (Java ObjectInputStream, PHP unserialize(), Python pickle, etc.)
       - Use safer alternatives like JSON, XML, or YAML with appropriate libraries
       - If native serialization is necessary, implement strict controls
    
    2. Input Validation
       - Validate all serialized data before deserialization
       - Implement schema validation
       - Use whitelisting instead of blacklisting
       - Validate data structure, types, and values
    
    3. Implement Class Restrictions
       - Use whitelists of allowed classes for deserialization
       - Implement serialization filters
       - Avoid deserializing arbitrary classes
    
    4. Integrity Verification
       - Implement cryptographic signatures for serialized data
       - Verify data integrity before deserialization
       - Use HMAC or digital signatures
    
    5. Resource Protection
       - Implement size limits for serialized data
       - Use timeouts for deserialization operations
       - Implement resource limits (memory, CPU)
       - Consider processing in isolated environments
    
    6. Secure Libraries and Dependencies
       - Keep all libraries and dependencies updated
       - Use security-focused serialization libraries
       - Regularly check for vulnerabilities in dependencies
    
    7. Monitoring and Logging
       - Implement proper logging for deserialization operations
       - Monitor for suspicious deserialization attempts
       - Implement alerts for potential attacks

    Preventing insecure deserialization requires a comprehensive approach that addresses multiple aspects of the deserialization process.

    Key prevention strategies:

    • Use safer alternatives to native serialization
    • Implement proper input validation and integrity verification
    • Restrict which classes can be deserialized
    • Protect against resource exhaustion
    • Keep all dependencies updated
    • Implement proper monitoring and logging
    • Follow the principle of defense in depth
    Cross-Site Request Forgery VulnerabilitiesSecurity Misconfiguration Vulnerabilities
    websitexgithublinkedin
    Powered by Mintlify
    Assistant
    Responses are generated using AI and may contain mistakes.