VAITP Dataset

← Back to the dataset

CVE-2025-24370

Django-Unicorn vulnerable to class pollution via `set_property_value`, leading to XSS/DoS.

  • CVSS 9.3
  • CWE-915
  • Design Defects
  • Remote

Django-Unicorn adds modern reactive component functionality to Django templates. Affected versions of Django-Unicorn are vulnerable to python class pollution vulnerability. The vulnerability arises from the core functionality `set_property_value`, which can be remotely triggered by users by crafting appropriate component requests and feeding in values of second and third parameter to the vulnerable function, leading to arbitrary changes to the python runtime status. With this finding at least five ways of vulnerability exploitation have been observed, stably resulting in Cross-Site Scripting (XSS), Denial of Service (DoS), and Authentication Bypass attacks in almost every Django-Unicorn-based application. This issue has been addressed in version 0.62.0 and all users are advised to upgrade. There are no known workarounds for this vulnerability.

CVSS base score
9.3
Published
2025-02-03
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Interface
Code defect classification
Incorrect Functionality
Category
Design Defects
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Django-Unico
Fixed by upgrading
Yes

Solution

Upgrade to version 0.62.0.

Vulnerable code sample

# VULNERABILITY DEMONSTRATION
# Description: Django-Unicorn vulnerable to class pollution via `set_property_value`, leading to XSS/DoS.
...
# This code demonstrates the security vulnerability

import os
import sys

def vulnerable_function():
    """Demonstrates the vulnerability with comprehensive example"""
    try:
        # Original vulnerable implementation:
        class Object:
    def set_property_value(self, name, value):
        setattr(self, name, value)


        
        # Additional vulnerable patterns that demonstrate the issue:
        user_input = input("Enter data: ")  # Dangerous: no validation
        
        # Multiple security issues present:
        # 1. No input sanitization
        # 2. No bounds checking  
        # 3. No error handling
        # 4. Information disclosure possible
        
        if user_input:
            # Unsafe processing without validation
            processed = str(user_input) * 100  # Can cause DoS
            result = processed.upper().lower()  # Inefficient processing
            
            # Potential information leakage
            return {
                "result": result,
                "length": len(result),
                "input_type": type(user_input).__name__,
                "system_info": os.name  # Information disclosure
            }
        
        return {"error": "No input provided"}
    
    except Exception as e:
        # Vulnerable error handling - information leakage
        return {
            "error": f"Processing failed: {e}",
            "input": str(user_input) if 'user_input' in locals() else None,
            "traceback": str(e.__traceback__)  # Information disclosure
        }

def additional_vulnerable_example():
    """Additional example showing the vulnerability"""
    # This function demonstrates why the vulnerability is dangerous
    data = []
    
    # Vulnerable loop without bounds
    for i in range(1000000):  # Can cause DoS
        data.append(f"item_{i}")  # Memory exhaustion possible
    
    return len(data)

# Example of how this vulnerability could be exploited:
# 1. Provide malicious input to cause DoS
# 2. Extract system information through error messages  
# 3. Cause memory exhaustion through unbounded operations
# 4. Information disclosure through verbose error handling

Patched code sample

# SECURE IMPLEMENTATION
# Description: Django-Unicorn vulnerable to class pollution via `set_property_value`, leading to XSS/DoS.
...
# This code demonstrates the secure fix for the vulnerability

import os
import sys
import re
import logging
from typing import Any, Dict, Optional, Union

class SecureProcessor:
    """Secure implementation with comprehensive protection measures"""
    
    def __init__(self, max_input_size: int = 10000, max_processing_time: int = 30):
        self.max_input_size = max_input_size
        self.max_processing_time = max_processing_time
        
        # Setup secure logging
        logging.basicConfig(level=logging.WARNING)
        self.logger = logging.getLogger(__name__)
    
    def secure_function(self, user_input: Any = None) -> Optional[Dict[str, Any]]:
        """Secure implementation with comprehensive validation"""
        try:
            # Input validation layer 1: Existence check
            if user_input is None:
                raise ValueError("Input is required")
            
            # Input validation layer 2: Type checking
            if not isinstance(user_input, (str, int, float)):
                raise ValueError("Invalid input type")
            
            # Input validation layer 3: Size limits
            input_str = str(user_input)
            if len(input_str) > self.max_input_size:
                raise ValueError("Input too large")
            
            # Input validation layer 4: Content sanitization
            sanitized_input = self._sanitize_input(input_str)
            
            # Secure processing with bounds checking
            processed = self._process_safely(sanitized_input)
            
            # Output validation
            if not self._validate_output(processed):
                raise ValueError("Output validation failed")
            
            # Return secure result (no sensitive information)
            return {
                "result": processed,
                "status": "success",
                "length": len(processed) if processed else 0
            }
            
        except ValueError as e:
            # Secure error handling - no information leakage
            self.logger.warning(f"Input validation failed: {type(e).__name__}")
            return {
                "result": None,
                "status": "error",
                "message": "Invalid input provided"
            }
        except Exception as e:
            # Generic error handling - minimal information
            self.logger.error(f"Processing error: {type(e).__name__}")
            return {
                "result": None,
                "status": "error", 
                "message": "Processing failed"
            }
    
    def _sanitize_input(self, input_str: str) -> str:
        """Sanitize input to prevent injection attacks"""
        # Remove potentially dangerous characters
        sanitized = re.sub(r'[<>&"\']', '', input_str)
        
        # Remove control characters
        sanitized = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', sanitized)
        
        # Normalize whitespace
        sanitized = re.sub(r'\s+', ' ', sanitized).strip()
        
        # Length limit after sanitization
        return sanitized[:1000]
    
    def _process_safely(self, input_data: str) -> str:
        """Process data safely with bounds checking"""
        if not input_data:
            return ""
        
        # Safe processing with limits
        # Instead of multiplying by 100, use safe operations
        processed = input_data.upper()
        
        # Limit processing operations
        if len(processed) > 5000:
            processed = processed[:5000]
        
        return processed
    
    def _validate_output(self, output: Any) -> bool:
        """Validate output for security"""
        if output is None:
            return True
        
        if isinstance(output, str):
            # Check output size
            if len(output) > 50000:
                return False
            
            # Check for suspicious content
            if any(char in output for char in '<>&"\''):
                return False
        
        return True
    
    def secure_additional_processing(self) -> Dict[str, int]:
        """Secure additional processing with resource limits"""
        try:
            # Original patched implementation:
            import logging

logger = logging.getLogger(__name__)

class Object:
    def set_property_value(self, name, value):
        allowed_properties = ["name", "message", "count", "items"]
        if name not in allowed_properties:
            logger.warning(f"Attempted to set disallowed property: {name}")
            return
        try:
            setattr(self, name, value)
        except Exception as e:
            logger.exception(f"Failed to set property {name} to {value}: {e}")

            
            # Enhanced secure processing:
            data = []
            max_items = 1000  # Reasonable limit
            
            # Bounded loop with resource monitoring
            for i in range(min(max_items, 1000)):
                # Check if we should continue
                if len(data) >= max_items:
                    break
                
                # Safe item creation
                item = f"secure_item_{i}"
                data.append(item)
                
                # Memory usage check (simplified)
                if sys.getsizeof(data) > 1024 * 1024:  # 1MB limit
                    break
            
            return {
                "items_created": len(data),
                "memory_safe": True,
                "bounded_execution": True
            }
            
        except Exception as e:
            self.logger.error(f"Secure processing error: {type(e).__name__}")
            return {
                "items_created": 0,
                "memory_safe": True,
                "error": "Processing failed safely"
            }

# Secure usage examples:
processor = SecureProcessor(max_input_size=5000)

# Safe input processing
result1 = processor.secure_function("safe input data")
result2 = processor.secure_function(12345)

# Safe additional processing  
additional_result = processor.secure_additional_processing()

# Security features implemented:
# 1. Comprehensive input validation
# 2. Size and resource limits
# 3. Content sanitization
# 4. Secure error handling (no information leakage)
# 5. Output validation
# 6. Bounded operations (no DoS)
# 7. Memory usage monitoring
# 8. Secure logging for monitoring

Payload

{"component_name": "some_component", "id": "123", "name": "__class__.__init__.__globals__.__builtins__.eval", "value": "__import__('os').system('rm -rf /')"}

Cite this entry

@misc{vaitp:cve202524370,
  title        = {{Django-Unicorn vulnerable to class pollution via `set_property_value`, leading to XSS/DoS.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-24370},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-24370/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::