Remote Code Execution via XMLDecoder Deserialization

Critical Risk deserialization
javadeserializationxmldecoderrcexml

What it is

Remote code execution vulnerabilities occur when untrusted XML data is deserialized using XMLDecoder, which can invoke arbitrary constructors and methods during the deserialization process.

@RestControllerpublic class ConfigController {        @PostMapping("/api/config")    public ResponseEntity<String> updateConfig(@RequestBody String xmlConfig) {        try {            // VULNERABLE: XMLDecoder with untrusted XML            XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(xmlConfig.getBytes()));            Object config = decoder.readObject();            decoder.close();                        // Process config...            return ResponseEntity.ok("Configuration updated");        } catch (Exception e) {            return ResponseEntity.status(500).body("Configuration failed");        }    }}
@RestControllerpublic class SecureConfigController {        @PostMapping("/api/config")    public ResponseEntity<String> updateConfig(@RequestBody String xmlConfig) {        try {            // SECURE: Use safe XML parsing with validation            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);                        DocumentBuilder builder = factory.newDocumentBuilder();            Document doc = builder.parse(new ByteArrayInputStream(xmlConfig.getBytes()));                        // Manual mapping to safe objects            ConfigObject config = parseConfigSafely(doc);                        return ResponseEntity.ok("Configuration updated safely");        } catch (Exception e) {            return ResponseEntity.status(500).body("Invalid configuration");        }    }        private ConfigObject parseConfigSafely(Document doc) {        // Safe manual parsing instead of automatic deserialization        Element root = doc.getDocumentElement();        ConfigObject config = new ConfigObject();                // Manually extract and validate each field        String name = root.getAttribute("name");        if (isValidConfigName(name)) {            config.setName(name);        }                return config;    }        private boolean isValidConfigName(String name) {        return name != null && name.matches("^[a-zA-Z0-9_-]+$");    }}

💡 Why This Fix Works

The vulnerable code was updated to address the security issue.

Why it happens

Using XMLDecoder.readObject() on user-provided XML, allowing arbitrary object instantiation and code execution.

Root causes

XMLDecoder on Untrusted Input

Using XMLDecoder.readObject() on user-provided XML, allowing arbitrary object instantiation and code execution.

Legacy Serialization Format

Maintaining XMLDecoder usage for backward compatibility with older Java Bean serialization formats.

Convenience Over Security

Using XMLDecoder for XML-to-object mapping without understanding its code execution risks.

Fixes

1

Replace with JSON or JAXB

Migrate from XMLDecoder to safer alternatives like JSON deserialization (Jackson, Gson) or JAXB for XML binding.

2

Never Use with Untrusted Input

If XMLDecoder must be used, only process XML from fully trusted sources, never from user input.

3

Implement Input Validation

Parse XML with SAX or DOM first to validate structure before any deserialization, rejecting suspicious elements.

Detect This Vulnerability in Your Code

Sourcery automatically identifies remote code execution via xmldecoder deserialization and many other security issues in your codebase.