Security overview The Blocklist XStream adapter is designed to protect against deserialization attacks while maintaining XStream functionality. This document explains the security model, threat landscape, and best practices.
Threat landscape
Deserialization vulnerabilities
XML deserialization attacks occur when malicious XML data causes the instantiation of dangerous classes that can:
Execute arbitrary system commands
Access sensitive files and system resources
Modify application state in unintended ways
Escalate privileges or bypass security controls
Common attack vectors
Gadget chains : Sequences of method calls triggered during deserialization
Process execution : Classes like ProcessBuilder that can run system commands
File system access : Classes that can read, write, or delete files
Network access : Classes that can make unauthorized network connections
Reflection abuse : Dynamic class loading and method invocation
Security architecture
Multi-layered protection
The adapter implements defense in depth through multiple security layers:
1
2 ┌─────────────────────────────────────┐
│ Application Layer │ ← Your application code
├─────────────────────────────────────┤
│ BlocklistRestrictedXStream │ ← Security enforcement
├─────────────────────────────────────┤
│ BlocklistConverter │ ← High-priority blocking
├─────────────────────────────────────┤
│ ConverterWrapper Layer │ ← Local converter protection
├─────────────────────────────────────┤
│ XStream Core │ ← Standard XStream functionality
└─────────────────────────────────────┘
Core security components
1. BlocklistConverter
Priority : 10 * XStream.PRIORITY_VERY_HIGH
Function : Blocks dangerous classes before any other converter can process them
Guarantee : Cannot be superseded by user-registered converters
2. BlocklistConverterWrapper
Function : Wraps local field converters with blocklist checking
Coverage : Ensures all deserialization paths are protected
Transparency : Maintains original converter behavior for allowed types
3. Allow rule validation
Function : Prevents explicit allowlisting of dangerous classes
Enforcement : Throws IllegalArgumentException for blocklisted types
Scope : Applies to all allowTypes() and allowTypeHierarchy() calls
Operating modes security comparison
Allowlist mode (default - maximum security)
1
2 XStream xstream = new BlocklistRestrictedXStream();
// Default behavior: deny all types
Security model : Zero trust - everything is denied by default
Protection level : Maximum
✅ Blocks all unknown types
✅ Blocks all blocklisted types
✅ Only processes explicitly allowed types
✅ Prevents accidental exposure of internal classes
Best practices :
Use for new applications
Use for processing untrusted input
Regularly audit allowed types
Prefer specific types over hierarchies
Blocklist mode (migration-friendly)
1
2 XStream xstream = new BlocklistRestrictedXStream();
xstream.addPermission(AnyTypePermission.ANY);
Security model : Trust with exceptions - allow everything except known bad
Protection level : Good
✅ Blocks all blocklisted types
❌ Allows unknown types by default
✅ Easy migration from unsafe XStream
⚠️ Requires vigilance for new threats
Best practices :
Use for legacy application migration
Monitor for unexpected type usage
Plan migration to allowlist mode
Combine with application-level input validation
Security guarantees
What is always protected
Blocklist enforcement : Classes on Atlassian's security blocklist are always blocked, regardless of mode
Converter priority : Security converters cannot be superseded
Local converter wrapping : All field-level converters are automatically secured
Allow rule validation : Dangerous classes cannot be explicitly allowed
What varies by mode
Security aspect Allowlist mode Blocklist mode Unknown types ❌ Blocked ✅ Allowed Known bad types ❌ Blocked ❌ Blocked Explicit allows ✅ Required ➖ Optional Migration effort 🔺 High 🔻 Low
Best practices
Development practices
Prefer allowlist mode for new applications
Minimize allowed types - only allow what you actually need
Avoid broad hierarchies - prefer specific classes over Object or interface hierarchies
Regular security reviews - audit allowed types periodically
Input validation - validate data beyond just type safety
Code examples
✅ Good: Specific type allowlisting
1
2 XStream xstream = new BlocklistRestrictedXStream();
xstream.allowTypes(new Class<?>[] {
UserProfile.class,
UserPreferences.class,
Address.class
});
❌ Bad: Overly broad allowlisting
1
2 // Don't do this - too permissive
xstream.allowTypeHierarchy(Object.class);
✅ Good: Gradual migration
1
2 // Step 1: Start with blocklist mode
XStream xstream = new BlocklistRestrictedXStream();
xstream.addPermission(AnyTypePermission.ANY);
// Step 2: Identify actual types used
// ... monitor and log types being processed ...
// Step 3: Migrate to allowlist mode
// xstream.removePermission(AnyTypePermission.ANY);
// xstream.allowTypes(identifiedTypes);
Operational practices
Monitor logs for ForbiddenClassException to detect attack attempts
Test thoroughly before deploying allowlist configurations
Document allowed types and their business justifications
Regular updates - keep blocklist adapter version current
Security testing - include deserialization attack scenarios in security tests
Known limitations
Scope of protection
Only applies to BlocklistRestrictedXStream instances
Does not protect direct XStream instantiation elsewhere in code
Runtime enforcement only - no compile-time checks
Detection and mitigation
Use the provided ArchUnit tests to detect direct XStream usage:
1
2 <!-- JUnit 5 version -->
<dependency>
<groupId>com.atlassian.security.serialblocklist</groupId>
<artifactId>blocklist-xstream-adapter-junit5</artifactId>
<scope>test</scope>
</dependency>