# LeoCRM Security Fix Plan ## Phase 1 — Kritische Sicherheitslücken (~8h) ### 1.1 ✅ 59 Permissions im Registry ergänzen - 98 Permissions in Routes verwendet, nur 39 in CORE_PERMISSIONS - Fehlend: ai:read, ai:write, automation:admin, mcp:read, mcp:write, calendar:read, dms:read, mail:read, tasks:read, tags:read, reports:read, search:read, agents:read, permissions:delegations:read, etc. - Status: Implementiert und committed ### 1.2 ✅ Grants einschränken (Migration 0100) - crm_api und crm_worker haben DELETE auf 12 sensitiven Tabellen: api_tokens, audit_log, notification_types, password_reset_tokens, plugin_allowlist, plugin_migrations, plugins, sessions, tenant_plugin_activation, tenants, user_tenants, users - Fix: DELETE für crm_api und crm_worker auf diesen Tabellen entfernen - crm_auth behält DELETE auf sessions + password_reset_tokens (für Logout/Reset) - Status: Migration erstellt und committed ### 1.3 ❌ RLS auf Tabellen — ENTFERNT - RLS auf sessions, password_reset_tokens, api_tokens, sequences, tenant_plugin_activation, user_tenants - PROBLEM: Diese Tabellen werden vor/ohne Tenant-Context abgefragt → RLS blockiert Login/App-Startup - WICHTIG: Kein RLS auf Tabellen die den Login blockieren! - Status: Komplett aus Migration entfernt. Tabellen haben kein RLS wie vor der Änderung ### 1.4 ✅ Mass-Assignment Schutz - UserCreate.role war setzbar (default viewer aber Client konnte admin senden) - UserUpdate.role war setzbar - Fix: UserCreate role=admin nur für is_system_admin. UserUpdate role=admin nur für is_system_admin - Status: Implementiert und committed ### 1.5 ✅ Entity Permission Ownership-Check (PUT) - PUT /permissions/{type}/{id}/{pid} hatte keinen Ownership-Check - DELETE hatte einen Check - Fix: _check_entity_ownership Hilfsfunktion, in PUT ergänzt - Status: Implementiert und committed ### 1.6 ✅ AttachmentResponse file_path entfernt - file_path: str in Schema Zeile 13 exponiert internen Storage-Pfad - Fix: Aus Schema entfernt - Status: Implementiert und committed ### 1.7 ✅ SystemSettings sensible Felder maskiert - tax_number, iban, bic in Response Schema für alle sichtbar - Fix: Für non-admin User maskiert ("********") - Status: Implementiert und committed ### 1.8 ✅ File Upload MIME-Validierung + Extensions - Nur Extension-Blocklist (ohne .php, .py, .asp, .jsp, .svg) + client-seitiger content_type (fälschbar) - Fix: BLOCKED_EXTENSIONS ergänzt (.php, .py, .pl, .asp, .aspx, .jsp, .svg, .htaccess, .phtml, .pht, .cgi, .cfm, .erb) + ALLOWED_MIME_PREFIXES Whitelist + MIME-Validierung in upload_file - Status: Implementiert und committed --- ## Phase 2 — Visibility Filter & Owner ID (~12h) ### 2.1 Visibility Filter in 17 Services einbauen - ai_assistant, ai_proactive, automation, entity_links, kommunikation, mail, mcp_client, permissions, report_generator, tags, tasks, entity_permission_service, user_service, workspace_service - apply_visibility_filter funktioniert korrekt (tenant_id + owner_id + shared permissions + admin bypass) ### 2.2 owner_id auf 26 Modellen ergänzen - Core (15): auth, contact_folder, contact_folder_permission, contact_merge, currency, entity_policy, group, guest_user, outbox, plugin, system_settings, tax, user, user_preference, workspace - Plugins (11): mcp_client, automation, unified_search, report_generator, entity_links, kommunikation, ai_proactive, ai_assistant, tags, permissions ### 2.3 EntityPermission Registry korrigieren - notification, contact_folder entfernen (kein owner_id) - entity_attachment, entity_history, subtask, calendar, folder hinzufügen --- ## Phase 3 — Weitere Sicherheitslücken (~4h) ### 3.1 WebSocket CSRF implementieren - Kommentar sagt "skip CSRF for now" — nicht implementiert - Fix: CSRF-Token aus Query-Parameter validieren ### 3.2 SameSite auf Lax - session_cookie_samesite = "strict" blockiert WebSocket - Fix: Auf "lax" ändern ### 3.3 Tenant FK CASCADE - 3 Tabellen ohne CASCADE (contact_merge_history, tenant_plugin_activation, user_tenants) - 10 Tabellen mit tenant_id aber ohne FK - Fix: CASCADE ergänzen, fehlende FKs hinzufügen --- ## Phase 4 — Krisensicherheit (~9h) ✅ Abgeschlossen ### 4.1 ✅ Redis Fallback / Graceful Degradation - Bei Redis-Ausfall funktioniert nichts mehr - Fix: Session-Check → DB-Fallback (sessions table), Permission-Cache → DB-Fallback (direct resolve), Rate-Limiting → in-memory Fallback (InMemoryRateLimiter) - Implementiert in: auth.py, permissions.py, rate_limit.py, middleware.py, deps.py ### 4.2 ✅ DB-Connection Retry - Bei kurzem DB-Ausfall gibt es sofort 500er - Fix: retry_db() mit exponentiellem Backoff (3 Versuche), 503 statt 500 bei endgültigem Ausfall - Implementiert in: db/__init__.py (get_db), resilience.py (retry_db) ### 4.3 ✅ Circuit Breaker Middleware - Bei wiederholten Fehlern kein automatisches Fallback - Fix: CircuitBreaker (5 Fehler in 30s → OPEN → 503 für 60s → HALF_OPEN → Probe → CLOSED/HALF_OPEN) - Implementiert in: resilience.py (CircuitBreaker, CircuitBreakerMiddleware), main.py (Middleware registriert) - 30/30 Tests bestanden, produktionsverifiziert (Health 200, Login 200) --- ## Phase 5 — Architektur-Lücken (~40h) — Teilweise erledigt ### 5.1 ✅ Öffentliche Plugin-Endpoints - Alle Plugin-Routes erforderten Auth - Fix: PluginRouteDef.is_public field, separate Router-Mountung ohne Auth-Dependency in main.py - permissions/public_routes.py: token-basierte Share-Link Zugriff (info, verify, download) - Produktionsverifiziert ### 5.2 ✅ PWA aktivieren - vite-plugin-pwa war installiert aber nicht konfiguriert - Fix: VitePWA in vite.config.ts konfiguriert (autoUpdate, workbox, runtime caching) - manifest.json mit Icons, theme-color, apple-mobile-web-app meta tags - Build generiert sw.js + workbox (90 precache entries) - Produktionsverifiziert ### 5.3 ✅ Contacts embedding + Auto-Index - contacts hatte KEINE embedding column im ORM model - Fix: Vector(768) embedding column zu Contact model hinzugefügt - Migration 0002_embeddings.sql existiert bereits (HNSW index) - ContactSearchProvider bereits implementiert (FTS + vector search) ### 5.4 ✅ Search Engine: alle Tabellen abdecken - Nur 5 Tabellen in Suche (contacts, mails, files, calendar_entries, companies) - Fix: 5 neue Search Provider: task, contactperson, tag, conversation, user - Total: 10 Search Provider (war 5) - Alle mit FTS search, tag auch mit vector search (384-dim) - provider_registry.py aktualisiert ### 5.5 ❌ Plugin-Marketplace — Nicht begonnen - Grundlage da (discover_external, plugin_allowlist, install from ZIP) - Fehlend: Echter Marketplace-Server, Plugin-Signatur-Verifikation, Plugin-Versionierung, UI ### 5.6 ❌ Agent Memory (persistent) — Nicht begonnen - Kein persistentes Agent Memory (nur Session-History) - Fix: agent_memories Tabelle mit embeddings, semantische Suche bei neuen Konversationen ### 5.7 ❌ GraphRAG als Provider — Nicht begonnen - Keine Graph-Struktur in DB oder Code - Fix: entity_relationships Tabelle, Graph-Traversal, als Provider in unified_search ### 5.8 ❌ Subagents / Multi-Agent — Nicht begonnen - Keine Subagents, keine Multi-Agent-Orchestrierung - automation/agent_comm.py hat Messaging-Infrastruktur - Fix: Agent kann Agent aufrufen, Agent-Coordinator ### 5.9 ❌ Agent von außen erreichbar — Nicht begonnen - Agent nur über WebUI erreichbar - Fix: API-Endpoint für externen Agent-Zugriff --- ## Verifizierte Fakten | Punkt | Ergebnis | |-------|---------| | 59 Permissions fehlen im Registry | ✅ Bestätigt | | crm_api + crm_worker DELETE auf 12 Tabellen | ✅ Bestätigt | | 5 Tabellen mit tenant_id aber ohne RLS | ✅ Bestätigt | | UserCreate.role setzbar | ✅ Bestätigt | | UserUpdate.role setzbar | ✅ Bestätigt | | PUT Entity Permission ohne Ownership-Check | ✅ Bestätigt | | AttachmentResponse.file_path exponiert | ✅ Bestätigt | | SystemSettings exponiert IBAN/BIC/Steuernummer | ✅ Bestätigt | | SameSite = strict | ✅ Bestätigt | | 17 Services ohne Visibility Filter | ✅ Bestätigt | | 26 Modelle ohne owner_id | ✅ Bestätigt | | WebSocket CSRF nicht implementiert | ✅ Bestätigt | | File Upload ohne echte MIME-Validierung | ✅ Bestätigt | | .env nicht in Git | ✅ Bereits gefixt | | password_reset_tokens RLS qual=true | ❌ War falsch — Tabelle hatte kein RLS | | DELETE Entity Permission ohne Ownership | ❌ War falsch — DELETE hat Check | --- ## WICHTIGE REGELN - KEIN manuelles Rumgepfusche auf der Produktions-DB - KEIN RLS auf Tabellen die den Login blockieren (sessions, password_reset_tokens, api_tokens, user_tenants, sequences, tenant_plugin_activation) - Deploy NUR über Coolify Tool (deploy_start) - Bei Deploy-Fehlern: Coolify DB nach Logs queryen, nicht manuell eingreifen - Login-Logik NIEMALS ändern