Files
leocrm/SECURITY_FIX_PLAN.md
T

9.1 KiB

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

  • Grundlage da (discover_external, plugin_allowlist, install from ZIP, signature.py)
  • Neu: marketplace/ Plugin mit MarketplaceListing model (global, keine tenant_id)
  • Endpoints: list, detail, install, verify, categories
  • Ed25519 Signatur-Verifikation via PluginSignature
  • Config: MARKETPLACE_SERVER_URL setting
  • Install-Flow: download → verify → install → activate

5.6 Agent Memory (persistent)

  • Neu: agent_memory/ Plugin mit AgentMemory model (embedding vector(768), HNSW index)
  • store_memory() mit auto-embedding
  • retrieve_relevant_memories() mit pgvector cosine similarity
  • Endpoints: create, list, search (semantisch), update, delete

5.7 GraphRAG als Provider

  • Neu: graph_rag/ Plugin mit EntityRelationship model
  • BFS Graph-Traversal (bidirektional, konfigurierbare Tiefe)
  • GraphRAGSearchProvider im unified_search registriert
  • Endpoints: create, list, traverse, delete

5.8 Subagents / Multi-Agent

  • AgentCoordinator Klasse (create_subtask, wait_for_subtask, aggregate, cancel)
  • AgentSubtask model + migration 0002_agent_subtasks.sql
  • 6 neue API Endpoints für Subtask-Management
  • Tools in AI tool registry registriert

5.9 Agent von außen erreichbar

  • external_api.py: POST /run, GET /status, POST /stream (SSE)
  • Bearer API Token Authentifizierung
  • Rate Limiting: 10 req/min per token
  • ExternalAgentRequest/Response schemas

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