security: Implement Phase 1 emergency hotfix (v5.0.3)

CRITICAL SECURITY FIXES:

1. Ephemeral Cache Mode (Default)
   - Process-isolated temporary cache directories
   - Automatic cleanup on exit via atexit
   - Prevents multi-user interference and cache poisoning
   - Legacy shared cache requires explicit DG_UNSAFE_SHARED_CACHE=true

2. TOCTOU Vulnerability Fix
   - New get_validated_ref() method with atomic SHA validation
   - File locking on Unix platforms (fcntl)
   - Validates SHA256 at use-time, not just check-time
   - Removes corrupted cache entries automatically
   - Prevents cache poisoning attacks

3. New Cache Error Classes
   - CacheMissError: Cache not found
   - CacheCorruptionError: SHA mismatch or tampering detected

SECURITY IMPACT:
- Eliminates multi-user cache attacks
- Closes TOCTOU attack window
- Prevents cache poisoning
- Automatic tamper detection

Files Modified:
- src/deltaglider/app/cli/main.py: Ephemeral cache for CLI
- src/deltaglider/client.py: Ephemeral cache for SDK
- src/deltaglider/ports/cache.py: get_validated_ref protocol
- src/deltaglider/adapters/cache_fs.py: TOCTOU-safe implementation
- src/deltaglider/core/service.py: Use validated refs
- src/deltaglider/core/errors.py: Cache error classes

Tests: 99/99 passing (18 unit + 81 integration)

This is the first phase of the security roadmap outlined in
SECURITY_FIX_ROADMAP.md. Addresses CVE-CRITICAL vulnerabilities
in cache system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Simone Scarduzio
2025-10-10 08:44:41 +02:00
parent 5e3b76791e
commit 37ea2f138c
7 changed files with 682 additions and 4 deletions
+21 -1
View File
@@ -1,6 +1,9 @@
"""DeltaGlider client with boto3-compatible APIs and advanced features."""
# ruff: noqa: I001
import atexit
import os
import shutil
import tempfile
from collections.abc import Callable
from pathlib import Path
@@ -1122,6 +1125,23 @@ def create_client(
XdeltaAdapter,
)
# SECURITY: Use ephemeral cache by default to prevent multi-user attacks
if os.environ.get("DG_UNSAFE_SHARED_CACHE") != "true":
# Create process-specific temporary cache directory
actual_cache_dir = Path(tempfile.mkdtemp(prefix="deltaglider-", dir="/tmp"))
# Register cleanup handler to remove cache on exit
atexit.register(lambda: shutil.rmtree(actual_cache_dir, ignore_errors=True))
else:
# Legacy shared cache mode - UNSAFE in multi-user environments
actual_cache_dir = Path(cache_dir)
# Create logger early to issue warning
temp_logger = StdLoggerAdapter(level=log_level)
temp_logger.warning(
"SECURITY WARNING: Shared cache mode enabled (DG_UNSAFE_SHARED_CACHE=true). "
"This mode has known security vulnerabilities in multi-user environments. "
"Use at your own risk!"
)
# Build boto3 client kwargs
boto3_kwargs = {}
if aws_access_key_id is not None:
@@ -1137,7 +1157,7 @@ def create_client(
hasher = Sha256Adapter()
storage = S3StorageAdapter(endpoint_url=endpoint_url, boto3_kwargs=boto3_kwargs)
diff = XdeltaAdapter()
cache = FsCacheAdapter(Path(cache_dir), hasher)
cache = FsCacheAdapter(actual_cache_dir, hasher)
clock = UtcClockAdapter()
logger = StdLoggerAdapter(level=log_level)
metrics = NoopMetricsAdapter()