# SECURITY FIXES CHECKLIST

## 20+ Specific Security Fixes Required

This document provides a detailed checklist of all security fixes identified in the comprehensive audit.

---

## CRITICAL FIXES (Must implement immediately)

### Fix 1: Remove shell=True from subprocess calls
**File:** `tools/terminal_tool.py`  
**Line:** ~457  
**CVSS:** 9.8

```python
# BEFORE
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ...)

# AFTER
# Validate command first
if not is_safe_command(exec_command):
    raise SecurityError("Dangerous command detected")
subprocess.Popen(cmd_list, shell=False, ...)  # Pass as list
```

---

### Fix 2: Implement path sandbox validation
**File:** `tools/file_operations.py`  
**Lines:** 409-420  
**CVSS:** 9.1

```python
# BEFORE
def _expand_path(self, path: str) -> str:
    if path.startswith('~'):
        return os.path.expanduser(path)
    return path

# AFTER
def _expand_path(self, path: str) -> Path:
    safe_root = Path(self.cwd).resolve()
    expanded = Path(path).expanduser().resolve()
    if not str(expanded).startswith(str(safe_root)):
        raise PermissionError(f"Path {path} outside allowed directory")
    return expanded
```

---

### Fix 3: Environment variable sanitization
**File:** `tools/code_execution_tool.py`  
**Lines:** 434-461  
**CVSS:** 9.3

```python
# BEFORE
_SAFE_ENV_PREFIXES = ("PATH", "HOME", "USER", ...)
_SECRET_SUBSTRINGS = ("TOKEN", "SECRET", ...)

# AFTER
_ALLOWED_ENV_VARS = frozenset([
    "PATH", "HOME", "USER", "LANG", "LC_ALL", 
    "TERM", "SHELL", "PWD", "PYTHONPATH"
])
child_env = {k: v for k, v in os.environ.items() 
             if k in _ALLOWED_ENV_VARS}
```

---

### Fix 4: Secure sudo password handling
**File:** `tools/terminal_tool.py`  
**Line:** 275  
**CVSS:** 9.0

```python
# BEFORE
exec_command = f"printf '%s\\n' {shlex.quote(sudo_stdin.rstrip())} | {exec_command}"

# AFTER
# Use file descriptor passing instead of command line
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
    f.write(sudo_stdin)
    pass_file = f.name
os.chmod(pass_file, 0o600)
exec_command = f"cat {pass_file} | {exec_command}"
# Clean up after execution
```

---

### Fix 5: Connection-level URL validation
**File:** `tools/url_safety.py`  
**Lines:** 50-96  
**CVSS:** 9.4

```python
# AFTER - Add to is_safe_url()
# After DNS resolution, verify IP is not in private range
def _validate_connection_ip(hostname: str) -> bool:
    try:
        addr = socket.getaddrinfo(hostname, None)
        for a in addr:
            ip = ipaddress.ip_address(a[4][0])
            if ip.is_private or ip.is_loopback or ip.is_reserved:
                return False
        return True
    except:
        return False
```

---

## HIGH PRIORITY FIXES

### Fix 6: MCP OAuth token validation
**File:** `tools/mcp_oauth.py`  
**Lines:** 66-89  
**CVSS:** 8.8

```python
# AFTER
async def get_tokens(self):
    data = self._read_json(self._tokens_path())
    if not data:
        return None
    # Add schema validation
    if not self._validate_token_schema(data):
        logger.error("Invalid token schema, deleting corrupted tokens")
        self.remove()
        return None
    return OAuthToken(**data)
```

---

### Fix 7: API Server SQL injection prevention
**File:** `gateway/platforms/api_server.py`  
**Lines:** 98-126  
**CVSS:** 8.5

```python
# AFTER
import uuid

def _validate_response_id(self, response_id: str) -> bool:
    """Validate response_id format to prevent injection."""
    try:
        uuid.UUID(response_id.split('-')[0], version=4)
        return True
    except (ValueError, IndexError):
        return False
```

---

### Fix 8: CORS strict validation
**File:** `gateway/platforms/api_server.py`  
**Lines:** 324-328  
**CVSS:** 8.2

```python
# AFTER
if "*" in self._cors_origins:
    logger.error("Wildcard CORS not allowed with credentials")
    return None  # Reject wildcard with credentials
```

---

### Fix 9: Require explicit API key
**File:** `gateway/platforms/api_server.py`  
**Lines:** 360-361  
**CVSS:** 8.1

```python
# AFTER
if not self._api_key:
    logger.error("API server started without authentication")
    return web.json_response(
        {"error": "Server authentication not configured"},
        status=500
    )
```

---

### Fix 10: CDP URL validation
**File:** `tools/browser_tool.py`  
**Lines:** 195-208  
**CVSS:** 8.4

```python
# AFTER
def _resolve_cdp_override(self, cdp_url: str) -> str:
    parsed = urlparse(cdp_url)
    if parsed.scheme not in ('ws', 'wss', 'http', 'https'):
        raise ValueError("Invalid CDP scheme")
    if parsed.hostname not in self._allowed_cdp_hosts:
        raise ValueError("CDP host not in allowlist")
    return cdp_url
```

---

### Fix 11: Skills guard normalization
**File:** `tools/skills_guard.py`  
**Lines:** 82-484  
**CVSS:** 7.8

```python
# AFTER - Add to scan_skill()
def normalize_for_scanning(content: str) -> str:
    """Normalize content to detect obfuscated threats."""
    # Normalize Unicode
    content = unicodedata.normalize('NFKC', content)
    # Normalize case
    content = content.lower()
    # Remove common obfuscation
    content = content.replace('\\x', '')
    content = content.replace('\\u', '')
    return content
```

---

### Fix 12: Docker volume validation
**File:** `tools/environments/docker.py`  
**Line:** 267  
**CVSS:** 8.7

```python
# AFTER
_BLOCKED_PATHS = ['/var/run/docker.sock', '/proc', '/sys', '/dev']
for vol in volumes:
    if any(blocked in vol for blocked in _BLOCKED_PATHS):
        raise SecurityError(f"Volume mount {vol} blocked")
    volume_args.extend(["-v", vol])
```

---

### Fix 13: Secure error messages
**File:** Multiple files  
**CVSS:** 7.5

```python
# AFTER - Add to all exception handlers
try:
    operation()
except Exception as e:
    logger.error(f"Error: {e}", exc_info=True)  # Full details for logs
    raise UserError("Operation failed")  # Generic for user
```

---

### Fix 14: OAuth state validation
**File:** `tools/mcp_oauth.py`  
**Line:** 186  
**CVSS:** 7.6

```python
# AFTER
code, state = await _wait_for_callback()
stored_state = storage.get_state()
if not hmac.compare_digest(state, stored_state):
    raise SecurityError("OAuth state mismatch - possible CSRF")
```

---

### Fix 15: File operation race condition fix
**File:** `tools/file_operations.py`  
**CVSS:** 7.4

```python
# AFTER
import fcntl

def safe_file_access(path: Path):
    fd = os.open(path, os.O_RDONLY)
    try:
        fcntl.flock(fd, fcntl.LOCK_SH)
        # Perform operations on fd, not path
        return os.read(fd, size)
    finally:
        fcntl.flock(fd, fcntl.LOCK_UN)
        os.close(fd)
```

---

### Fix 16: Add rate limiting
**File:** `gateway/platforms/api_server.py`  
**CVSS:** 7.3

```python
# AFTER - Add middleware
from aiohttp_limiter import Limiter

limiter = Limiter(
    rate=100,  # requests
    per=60,    # per minute
    key_func=lambda req: req.remote
)

@app.middleware
async def rate_limit_middleware(request, handler):
    if not limiter.is_allowed(request):
        return web.json_response(
            {"error": "Rate limit exceeded"}, 
            status=429
        )
    return await handler(request)
```

---

### Fix 17: Secure temp file creation
**File:** `tools/code_execution_tool.py`  
**Line:** 388  
**CVSS:** 7.2

```python
# AFTER
import tempfile
import os

fd, tmpdir = tempfile.mkstemp(prefix="hermes_sandbox_", suffix=".tmp")
os.chmod(tmpdir, 0o700)  # Owner only
os.close(fd)
# Use tmpdir securely
```

---

## MEDIUM PRIORITY FIXES

### Fix 18: Expand dangerous patterns
**File:** `tools/approval.py`  
**Lines:** 40-78  
**CVSS:** 6.5

Add patterns:
```python
(r'\bcurl\s+.*\|\s*sh\b', "pipe remote content to shell"),
(r'\bwget\s+.*\|\s*bash\b', "pipe remote content to shell"),
(r'python\s+-c\s+.*import\s+os', "python os import"),
(r'perl\s+-e\s+.*system', "perl system call"),
```

---

### Fix 19: Credential file permissions
**File:** `tools/credential_files.py`, `tools/mcp_oauth.py`  
**CVSS:** 6.4

```python
# AFTER
def _write_json(path: Path, data: dict) -> None:
    path.write_text(json.dumps(data, indent=2), encoding="utf-8")
    path.chmod(0o600)
    # Verify permissions were set
    stat = path.stat()
    if stat.st_mode & 0o077:
        raise SecurityError("Failed to set restrictive permissions")
```

---

### Fix 20: Log sanitization
**File:** Multiple logging statements  
**CVSS:** 5.8

```python
# AFTER
from agent.redact import redact_sensitive_text

# In all logging calls
logger.info(redact_sensitive_text(f"Processing {user_input}"))
```

---

## ADDITIONAL FIXES (21-32)

### Fix 21: XXE Prevention
**File:** PowerPoint XML processing  
Add:
```python
from defusedxml import ElementTree as ET
# Use defusedxml instead of standard xml
```

---

### Fix 22: YAML Safe Loading Audit
**File:** `hermes_cli/config.py`  
Audit all yaml.safe_load calls for custom constructors.

---

### Fix 23: Prototype Pollution Fix
**File:** `scripts/whatsapp-bridge/bridge.js`  
Use Map instead of Object for user-controlled keys.

---

### Fix 24: Subagent Isolation
**File:** `tools/delegate_tool.py`  
Implement filesystem namespace isolation.

---

### Fix 25: Secure Session IDs
**File:** `gateway/session.py`  
Use secrets.token_urlsafe(32) instead of uuid4.

---

### Fix 26: Binary Integrity Checks
**File:** `tools/tirith_security.py`  
Require GPG signature verification.

---

### Fix 27: Debug Output Redaction
**File:** `tools/debug_helpers.py`  
Apply redact_sensitive_text to all debug output.

---

### Fix 28: Security Headers
**File:** `gateway/platforms/api_server.py`  
Add:
```python
"Content-Security-Policy": "default-src 'self'",
"Strict-Transport-Security": "max-age=31536000",
```

---

### Fix 29: Version Information Minimization
**File:** Version endpoints  
Return minimal version information publicly.

---

### Fix 30: Dead Code Removal
**File:** Multiple  
Remove unused imports and functions.

---

### Fix 31: Token Encryption at Rest
**File:** `hermes_cli/auth.py`  
Use OS keychain or encrypt auth.json.

---

### Fix 32: Input Length Validation
**File:** All tool entry points  
Add MAX_INPUT_LENGTH checks everywhere.

---

## IMPLEMENTATION VERIFICATION

### Testing Requirements
- [ ] All fixes have unit tests
- [ ] Security regression tests pass
- [ ] Fuzzing shows no new vulnerabilities
- [ ] Penetration test completed
- [ ] Code review by security team

### Sign-off Required
- [ ] Security Team Lead
- [ ] Engineering Manager
- [ ] QA Lead
- [ ] DevOps Lead

---

**Last Updated:** March 30, 2026  
**Next Review:** After all P0/P1 fixes completed
