VAITP Dataset

← Back to the dataset

CVE-2020-5215

String to tf.float16 conversion in TensorFlow <=1.15.2 and 2.0.1 causes segmentation fault in eager mode, potential DoS

  • CVSS 7.5
  • CWE-20 Improper Input Validation
  • Input Validation and Sanitization
  • Remote

In TensorFlow before 1.15.2 and 2.0.1, converting a string (from Python) to a tf.float16 value results in a segmentation fault in eager mode as the format checks for this use case are only in the graph mode. This issue can lead to denial of service in inference/training where a malicious attacker can send a data point which contains a string instead of a tf.float16 value. Similar effects can be obtained by manipulating saved models and checkpoints whereby replacing a scalar tf.float16 value with a scalar string will trigger this issue due to automatic conversions. This can be easily reproduced by tf.constant("hello", tf.float16), if eager execution is enabled. This issue is patched in TensorFlow 1.15.1 and 2.0.1 with this vulnerability patched. TensorFlow 2.1.0 was released after we fixed the issue, thus it is not affected. Users are encouraged to switch to TensorFlow 1.15.1, 2.0.1 or 2.1.0.

CVSS base score
7.5
Published
2020-01-28
OWASP
A05 Security Misconfiguration
Orthogonal defect classification
Checking
Code defect classification
Incorrect Check
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
TensorFlow
Fixed by upgrading
Yes

Solution

Update to TensorFlow 1.15.1, 2.0.1, or 2.1.0.

Vulnerable code sample

# VULNERABILITY DEMONSTRATION
# Description: String to tf.float16 conversion in TensorFlow <=1.15.2 and 2.0.1 causes segmentation fault in eager ...
# This code demonstrates the security vulnerability

import os
import sys

def vulnerable_function():
    """Demonstrates the vulnerability with comprehensive example"""
    try:
        # Original vulnerable implementation:
        import tensorflow as tf

value = tf.constant("hello", dtype=tf.float16)
        
        # 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: String to tf.float16 conversion in TensorFlow <=1.15.2 and 2.0.1 causes segmentation fault in eager ...
# 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:
            from packaging import version
import tensorflow as tf

current_version = version.parse(tf.__version__)
min_safe_version = version.parse("2.0.1")

assert current_version >= min_safe_version, "TensorFlow version is vulnerable!"

            
            # 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

Cite this entry

@misc{vaitp:cve20205215,
  title        = {{String to tf.float16 conversion in TensorFlow <=1.15.2 and 2.0.1 causes segmentation fault in eager mode, potential DoS}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2020},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2020-5215},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2020-5215/}}
}
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 ::