Issues fixed:
1. [CRITICAL] No authentication on destructive routes (CWE-306)
POST /api/system/cleanup/docker was unauthenticated (system_bp is
CSRF-exempt, before_request only refreshes session, no login check).
Any unauthenticated HTTP client could trigger docker system prune.
Fix: _require_internal_key() checks X-Internal-Key header against
INTERNAL_API_KEY env var on all 4 routes; fail-secure if key unset.
2. [MEDIUM] Unvalidated numeric inputs in find commands (CWE-20)
max_size_mb / older_than_hours came from POST body and were
interpolated into find -size / -mmin args. Negative/huge values
could cause unexpected behavior.
Fix: _validate_int() clamps to [1..10000] / [1..8760] with defaults.
3. [LOW] find -mmin arg missing leading '+' (logic bug)
'-mmin 168' matches FILES EXACTLY 168 min old, not older-than.
Fix: '-mmin', f'+{older_than_hours * 60}' (+ = older than)
4. [LOW] subprocess(['date', ...]) in health_check replaced
with Python datetime.now(UTC).isoformat() — no subprocess needed.
INTERNAL_API_KEY added to .env.example with generation instructions.
Generate with: openssl rand -hex 32
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>