ILLUMENTIS.
EN

Illumentis — Sicherheit & Transparenz

Zusammenfassung aller implementierten Sicherheitsmaßnahmen, Gates und Konfigurationen — als Grundlage für ein externes Security-Review.

Stand: 26. September 2026 Phase: Beta (Strato, geteilter Host) — Produktivumgebung (Hetzner) noch nicht live Primärquelle: illumentis-security-testing-lawbook.md (verbindliches, versioniertes Regelwerk)

Was dieses Dokument ist: eine konsolidierte Selbstauskunft über den aktuellen technischen und organisatorischen Sicherheitsstand — jede Maßnahme ist im Code oder in der Serverkonfiguration real vorhanden und überwiegend automatisiert getestet, nicht nur geplant. Wo eine Maßnahme noch aussteht, ist das explizit als solche markiert statt verschwiegen.

Was dieses Dokument nicht ersetzen kann: einen tatsächlich durchgeführten, unabhängigen externen Penetrationstest. Diese Übersicht ist die Grundlage für ein solches Review, nicht dessen Ergebnis.

Hosting
Ausschließlich EU-Anbieter, kein US-Hyperscaler — CLOUD-Act-Vermeidung
Selbsthosting
Git, Fehler-Tracking, Grammatik-Check, Malware-Scan, Secrets — alles selbst betrieben statt SaaS
Fail-Closed
Sicherheitskontrollen lehnen bei Unsicherheit ab, statt stillschweigend durchzulassen
Verteidigung in der Tiefe
Voter + Serializer-Groups + Tenant-Filter + Verschlüsselung als unabhängige Schichten

1 Authentifizierung & Zugriffskontrolle

Passwort-Hashing implementiert

bcrypt/Argon2id über UserPasswordHasherInterface, Mindest-Kostenfaktor bewusst festgelegt und getestet (PasswordHashingCostFactorTest) statt Framework-Default zu vertrauen. Echter Fund 2026-09-25: der Argon2id-Dummy-Hash zur Login-Anti-Enumeration war mit dem Default-time_cost auf der realen Server-Hardware messbar schneller als ein echter bcrypt-Login — per externem Timing-Test entdeckt, empirisch (nicht aus Tabellenwerten) auf annähernde Gleichzeitigkeit nachkalibriert.

Timing-Enumeration bei Passwort-vergessen/Registrierung implementiert (2026-09-25)

Derselbe externe Test zeigte einen kleineren, aber messbaren Rest-Unterschied bei forgot-password/self-register (synchroner DB-Lookup nur im Treffer-Fall). Strukturell statt kostenangeglichen gelöst: der komplette asymmetrische Teil (Lookup, Verzweigung, Mailversand) läuft jetzt in einem asynchronen Message-Handler — der Controller selbst leistet für jede E-Mail exakt dieselbe, konstante Arbeit. Live re-verifiziert: Antwortzeit für existierenden vs. frei erfundenen Account nicht mehr unterscheidbar.

Zwei-Faktor-Authentifizierung (TOTP) implementiert

Verpflichtend für alle Admin-Rollen, optional für reguläre Accounts. Backup-Codes gehasht, einmalig im Klartext gezeigt. Eigener Fund behoben: TOTP-Testflake per gefrorener Uhr gelöst, Produktions-Toleranz (leeway=0) bewusst unverändert streng gelassen.

Rate-Limiting implementiert

Eigene Policy für Login, 2FA, Registrierung, KI-Endpunkte — jeweils mit echter symfony/lock-Synchronisierung (sonst unsynchronisiert unter Last).

Invite-/Reset-Token implementiert

Kryptographisch sichere Zufallszahlen (random_bytes()), nie mt_rand(). Zeitsicherer Vergleich (hash_equals()), einheitliche Fehlermeldung unabhängig von Trefferquote.

Autorisierung ausschließlich über Voters implementiert

Nie Ad-hoc-if-Prüfungen. Vollständige Owner/Co-Autor/Gast/Admin-Matrix, vier abgestufte Gast-Stufen, Zwei-Stufen-Entfernung bei Co-Autoren.

API-Dokumentation nicht anonym einsehbar implementiert (2026-09-25)

Externer Scan fand: /api/docs legte das OpenAPI-Schema (Feldnamen wie canManageUsers) auch für anonyme Besucher offen — kein Datenleck (die eigentlichen Endpunkte waren bereits korrekt geschützt), aber unnötige Struktur-Aufklärung. Jetzt Login-Pflicht für den Dokumentations-Endpunkt.

Platform-Owner-Kontinuität implementiert

Co-Owner, befristete Nachfolge-Delegation, Master-Recovery (zwei getrennte physische Geheimnisse + Mehrheitszustimmung) — kein Single Point of Failure bei Verlust des einzigen Admin-Zugangs.

Admin-Reset & Security-Freeze implementiert

Jeder administrative 2FA-/Passwort-Reset erzeugt einen unveränderlichen (append-only) Audit-Log-Eintrag. Vier-Augen-Prinzip sobald ≥2 Admin-Accounts existieren. E-Mail-Änderung ausschließlich Self-Service, nie über einen Admin-Endpunkt.

Session-/Geräteverwaltung implementiert

Fernsperre bei Geräteverlust (Remote-Wipe-Signal), Idempotency-Keys gegen doppelte Verarbeitung bei Offline-Reconnect — systemweit über #[IdempotencyStrategy] erzwungen, nicht optional pro Endpunkt.

2 Verschlüsselung & Datensicherheit

Field-Level Encryption implementiert

Kapitel-Inhalte und Versions-Snapshots vor dem Schreiben verschlüsselt (Sodium/XChaCha20-Poly1305), gekapselt in einem eigenen Doctrine-Type.

Envelope Encryption (KEK→DEK) implementiert

Selbstgehosteter HashiCorp Vault, echte 2-von-3-Unseal-Schwelle (kein Solo-Schlüssel). Restore-Drill real durchgeführt und bestanden, nicht nur konfiguriert.

E-Mail-Blind-Index implementiert

users.email verschlüsselt gespeichert, zusätzlicher HMAC-SHA256-Hash für Login-/Eindeutigkeitsprüfung — kein Klartext-Vergleich auf sensibler Spalte.

Tenant-Isolation implementiert

Globaler Doctrine-SQL-Filter schränkt jede Query automatisch auf erlaubte Projekte ein — zusätzlich zur Voter-Prüfung, nicht als Ersatz. Fail-closed-Zweig bewusst ungeloggt (Tripwire).

PostgreSQL Least-Privilege implementiert

Anwendungsrolle nur mit DML-Rechten, kein SUPERUSER. Getrennte App-/Batch-Rolle, Batch-User ohne Zugriff auf E-Mail/Passwort-Hash-Spalten.

Primärschlüssel als ULID implementiert

Statt INT AUTO_INCREMENT — verhindert Enumerierbarkeit von Bestandsgrößen. Ungültiges ID-Format liefert 400, nie 500.

Kein serverseitiges Zero-Knowledge bewusste Grenze, offen kommuniziert

Manuskripte sind serverseitig lesbar (Suche, Kontinuitätsprüfung, Kollaboration erfordern das) — ehrlich als Architekturentscheidung dokumentiert, nie als „Ende-zu-Ende-verschlüsselt" beworben.

3 Input-Validierung, Datei-Uploads & Malware-Schutz

AST-Sanitisierung (Editor-Inhalte) implementiert

Rekursive Allowlist statt HTMLPurifier — TipTap-Inhalte sind JSON, kein roher HTML-String. Unbekannter Node-Typ → vollständige Ablehnung, nie stilles Entfernen. Tiefen-/Größenlimits gegen Payload-Bomben.

Datei-Upload-Validierung implementiert

Echtes Content-Sniffing (finfo, nie Client-Angabe), harte MIME-Allowlist, Größenlimits, selbst generierte Dateinamen (strukturell kein Pfad-Traversal möglich).

Malware-Scan bei Uploads implementiert (2026-09-25)

Selbstgehostetes ClamAV (kein SaaS-Anbieter), fail-closed — Scanner nicht erreichbar = Upload abgelehnt, nie ungescannt durchgelassen. Real mit EICAR-Testdatei verifiziert, Speicherlimit gegen Ressourcen-Erschöpfung gesetzt.

ZIP-Bomben / XXE (Import) implementiert

Zielgröße jedes Archiv-Eintrags vor dem Entpacken geprüft. LIBXML_NONET explizit aktiviert, DTD-Laden deaktiviert bei jedem XML-Parsing im Import-Pfad.

SSRF-Schutz implementiert

Jeder serverseitige Outbound-Call gegen eine feste Domain-Allowlist geprüft — kein „Import von beliebiger URL"-Feature, das das umgehen könnte. Export-Rendering-Pipeline ohne Netzwerkzugriff außer eigener Whitelist.

Mass-Assignment-Schutz implementiert

Ausschließlich dedizierte Write-DTOs, nie generische Entity-Hydrierung. Kein Endpunkt mappt einen Request-Body direkt auf eine Entity.

Sicherheits-Header bei Datei-Auslieferung implementiert

X-Content-Type-Options: nosniff global, Content-Disposition bei jedem Datei-Endpunkt — Tiefenverteidigung zusätzlich zur MIME-Allowlist.

4 Netzwerk, Transport & Frontend

HTTPS/HSTS/CSP implementiert

HTTPS erzwungen (nicht nur applikationsseitig), Strict-Transport-Security, restriktive Content-Security-Policy (connect-src 'self' — verhindert Datenexfiltration bei hypothetischem XSS). Kein KI-Provider in der Allowlist. Echter Fund 2026-09-25: galt bisher nur für Antworten, die tatsächlich durch die Backend-Anwendung liefen — die vom Webserver direkt ausgelieferte SPA-Hülle (HTML/Assets) hatte dieselben Header schlicht nicht. Beide Ausliefer-Pfade jetzt mit identischen Werten abgesichert.

Referrer-Policy / Permissions-Policy / X-Frame-Options implementiert (2026-09-25)

Externer Scan-Fund: bislang gar nicht gesetzt. strict-origin-when-cross-origin statt Browser-Default nur implizit zu vertrauen; Permissions-Policy deaktiviert nachweislich ungenutzte Browser-Features (Kamera, Geolocation, Payment …); X-Frame-Options: DENY als Fallback für Browser ohne CSP-Level-2-Support (frame-ancestors deckt moderne Browser bereits ab).

CORS implementiert

Ausschließlich exakte, hartcodierte Domains bei allow_credentials — nie Wildcard-Regexes über Domain-Familien.

CSRF-Schutz implementiert

SameSite-Cookie plus Pflicht-Header X-Requested-With bei jedem mutierenden Request.

Kein v-html im Frontend implementiert

Nirgends im Code verwendet (bewusst, per Kommentar dokumentiert) — Editor-Rendering läuft ausschließlich über TipTaps eigenes, geschlossenes Schema.

Client-seitiger Schutzschirm implementiert (optional)

Opt-in-Funktion für geteilte Geräte — schnelles Verbergen sensibler Inhalte.

Browser-Mindestanforderungen kommuniziert implementiert (2026-09-25)

Explizite browserslist-Baseline statt einer impliziten Build-Tool-Annahme. Feature-Detection-Skript (ES5, vor dem eigentlichen Bundle geladen) zeigt bei zu altem Browser einen Hinweis — kein Hard-Block, reine Nutzerfreundlichkeit statt Sicherheitsentscheidung.

5 Infrastruktur & Betrieb (Strato-Beta, heute real gehärtet)

Host-Firewall implementiert

Eigene, Docker-verträgliche INPUT-Ketten-Firewall (Default-Deny mit Allowlist) — bewusst nicht die Plesk-Firewall, deren generiertes Skript nachweislich den gesamten Container-Stack vom Netz getrennt hätte.

fail2ban implementiert

Reale nftables-Integration (Docker-Host-spezifischer Stolperstein gefunden und behoben), real mit Dummy-IP verifiziert — nicht nur konfiguriert, sondern eine echte Netzwerkregel bei einem Bann bestätigt.

SSH-Härtung implementiert

Ausschließlich Key-Auth, kein Passwort-Login.

UID-Isolation zwischen Diensten implementiert

Web-App und Git-/CI-Server liefen zunächst unter derselben Host-UID (ein RCE in der größeren, exponierten App hätte automatisch Zugriff auf den Git-Server gehabt) — behoben, dedizierte System-User pro Dienst, als generelles Prinzip festgehalten.

Dateisystem-Rechte implementiert

Repo-Verzeichnis war versehentlich weltlesbar (für andere, fremde Accounts auf dem geteilten Host) — real mit einem fremden Account nachgewiesen und geschlossen. Backup-Verschlüsselungscode aus der Crontab in eine eigene 0600-Datei ausgelagert.

Branch-Protection implementiert

Kein direkter Push auf main — real getestet, ein Push-Versuch wurde tatsächlich zurückgewiesen. Pflicht-CI-Checks vor jedem Merge.

Fail-closed CI/CD-Deploy implementiert

Automatischer Staging-Deploy nur bei grüner CI — negativer Pfad real getestet (rote Checks lösten nachweislich keinen Deploy aus). Deploy-Token least-privilege (read:repository, kein Schreibzugriff, kein SSH-Key).

Backup & Restore implementiert, real getestet

Verschlüsselte Backups (Vault, Git-Server, Datenbank), Restore-Drills tatsächlich durchgeführt und bestanden — nicht nur als Skript vorhanden.

OOM-Härtung (Malware-Scanner) implementiert

Explizites Speicherlimit für den ClamAV-Container, damit ein Ressourcen-Ausreißer nie den geteilten Host statt nur diesen einen Dienst trifft.

Messenger-Worker (Hintergrund-Warteschlange) implementiert (2026-09-25)

Echter Fund bei der Timing-Fix-Umsetzung: kein Prozess konsumierte bislang die asynchrone Nachrichten-Warteschlange — mehrere Nachrichten hingen real unverarbeitet in der Datenbank. Eigener Worker-Container (gleiches Image, messenger:consume), wird durch dasselbe Compose-File automatisch bei jedem Deploy mitgeführt.

Deploy-Automatisierung: Config-Änderungen zuverlässig live implementiert (2026-09-25, Selbstaudit-Fund)

Bei der Nachprüfung der eigenen heutigen Änderungen festgestellt: eine geänderte Webserver-Konfiguration (Bind-Mount) wurde vom automatischen Deploy zwar ausgecheckt, aber nie tatsächlich neu geladen, ohne einen zusätzlichen manuellen Schritt — der reine Merkregel-Charakter führte genau einmal zum Vergessen. Jetzt fester, bedingungsloser Teil des Deploy-Skripts, kein manueller Schritt mehr nötig. Zeigt die eigene Prüfdisziplin: der Fund kam aus einer Nachverifikation der eigenen Arbeit, nicht von außen.

6 Selbsthosting-Prinzip & Cloud-Act-Vermeidung

Durchgängiges Architekturprinzip, nicht nur bei einem Dienst: ausschließlich EU-Hosting (Hetzner/Strato), keine US-Hyperscaler (AWS/Google Cloud/Azure) und keine US-SaaS-Anbieter für sicherheitsrelevante Funktionen — wegen des US CLOUD Act (extraterritorialer Datenzugriffs-Anspruch, unabhängig vom physischen Speicherort).

7 Datenschutz & Betroffenenrechte (DSGVO)

Vollständiger Datenexport implementiert

Technische Erfüllung von Art. 20 DSGVO — auf jedem Plan kostenlos, darf laut Grundsatz nie zum Bezahl-Feature werden. Konto- und projektbezogene Daten getrennt, jeweils vollständig (mehrfach real gegen alle ~170 Entitätstypen abgeglichen).

Zugriffs-Transparenz implementiert

Jeder Gast-Zugriff auf freigegebene Inhalte wird protokolliert und ist für Owner/Co-Autoren einsehbar.

Löschungs-Ausnahmeregel implementiert

Art. 17 Abs. 3 lit. b DSGVO — eng begrenzte Ausnahme nur bei offenem Rechenschaftspflicht-Vorgang, nie eine pauschale Verzögerung der gesamten Löschung.

Datenminimierung implementiert

Gast-Accounts erhalten nur, was für die konkrete Freigabe nötig ist. Nie angenommene Einladungen werden nach 14 Tagen automatisch anonymisiert.

Keine Dritt-Tracker implementiert

Keine Werbe-/Analytics-Cookies, kein Cross-Site-Tracking. Performance-Telemetrie nie still im Hintergrund — jede Übertragung erzeugt eine sichtbare Meldung.

8 Governance & Testdisziplin

Sicherheitsanforderungen sind in einem einzigen, verbindlichen Regelwerk konsolidiert (illumentis-security-testing-lawbook.md, ~1000 Zeilen) — additiv-only: es wird nie etwas gekürzt oder abgeschwächt, ohne explizite Rückfrage. Jede sicherheitsrelevante Maßnahme wird durch eine automatisierte Testklasse validiert, nicht durch manuelle Prüfung allein.

9 Monatlicher Red-Team-Validierungsbericht (September 2026)

14 Angriffsszenarien geprüft — 13 davon mit konkreten automatisierten Tests verifiziert. Identifizierte Schwachstellen wurden behoben und erneut getestet, eine bekannte Einschränkung ist dokumentiert statt verschwiegen. Aktueller Testlauf: 3.896 automatisierte Tests, 2 Testfehler im letzten Lauf, 1 bekannter unabhängiger Risky-Test wird separat verfolgt.

AngriffsszenarioErgebnis
Compromised Userbestanden
Cross-Tenant IDORbestanden
Compromised Co-Authorbestanden
Compromised Editorbestanden
Compromised Adminbestanden — mit dokumentierten Grenzen
Session Hijackingbestanden — mit dokumentierten Grenzen
Race Conditionsbestanden
API Manipulationbestanden
Vault Policy Bypassbestanden
Authenticated Scrapingbestanden
Branch/Merge Manipulationbestanden
Permission Escalationbestanden
Compromised Symfony Runtimebestanden — mit dokumentierten Grenzen
Deployment Integritybekannte verbleibende Maßnahme

Was diese Tests nicht beweisen

Die beschriebenen Tests stellen keine Garantie gegen zukünftige Sicherheitslücken dar. Sie prüfen definierte Sicherheitseigenschaften unter den dokumentierten Voraussetzungen — die vier folgenden Fälle wurden bewusst mit ihren jeweiligen Grenzen dokumentiert statt als vollständig gelöst dargestellt.

Compromised Admin dokumentierte Grenze

Das Prinzip „kein Admin sieht Buchinhalte" gilt vollständig für den App-Admin (can_manage_users) über die Anwendung selbst (Voter, Serializer Groups, Field-Level Encryption). Es gilt NICHT gegen einen Server-Root-/Infrastruktur-Admin: der kann den KEK aus Symfony Secrets/der Umgebungsvariable auslesen. Echte Wirksamkeit auch gegen kompromittierten Root-Zugriff bräuchte einen externen KMS/Vault, der selbst entschlüsselt (Chiffretext rein, Klartext raus, Schlüssel verlässt den Key-Server nie) — für content/media/email-hash bereits umgesetzt (siehe Vault Policy Bypass/Compromised Symfony Runtime), aber noch nicht für jeden Datenpfad.

Session Hijacking dokumentierte Grenze

Die Erkennung vergleicht bewusst nur den User-Agent, nicht die IP-Adresse (ein Netzwerkwechsel mitten in einer legitimen Sitzung ist normal). Ein Angreifer, der IP UND User-Agent des Opfers exakt nachbildet, bleibt unentdeckt.

Compromised Symfony Runtime dokumentierte Grenze

Ein kompromittierter, aktiv laufender Symfony-Prozess kann zum Zeitpunkt des Zugriffs im Prozessspeicher vorhandene Klartext-Schlüssel bzw. bereits entschlüsselte Daten erreichen. Die Vault-Architektur (Envelope Encryption) reduziert insbesondere das Risiko eines dauerhaft verfügbaren, statischen Anwendungsschlüssels — sie verhindert keinen vollständigen Live-RCE.

Deployment Integrity bekannte offene Maßnahme

File-Integrity-Monitoring (Erkennung nachträglicher Code-Manipulation) existiert und ist getestet. Automatisierte Deployment-Härtung (signiertes Manifest, SHA-Pinning, externe Out-of-Band-Verifikation) ist dokumentiertes Wissen, aber noch keine laufende Maßnahme.

10 Ehrliche Bestandsaufnahme — was ein externer Auditor zusätzlich prüfen würde

Aus dem Lawbook-Abschnitt „Externe Prüfbarkeit" übernommen — Selbstauskunft ist keine externe Bestätigung. Diese Tabelle unterscheidet bewusst zwischen beidem.

BereichStatus
Auth, Autorisierung, IDOR, Verschlüsselung, Input-ValidierungVollständig abgedeckt, automatisiert getestet
Netzwerk/Transport, DNS-/E-Mail-Authentifizierung (SPF/DKIM/DMARC)Abgedeckt
Backup/Disaster-Recovery, Incident-Response-PlanAbgedeckt, Restore real getestet
Secret-Scanning in CI (Gitleaks)Implementiert (2026-09-25) — echter Konfigurationsfehler beim Aufbau real gefunden und behoben (fehlendes useDefault=true hätte alle Regeln stillschweigend deaktiviert)
Lizenzprüfung gegen Allowlist (Abhängigkeiten)Implementiert (2026-09-25), Backend + Frontend, fail-closed bei fehlender Lizenzangabe
Automatisierte Coverage-Schwellen-ErzwingungImplementiert (2026-09-26) — PCOV in CI, Schwellen nach echtem Messlauf auf 90%/80% angehoben. Alle 101 dabei gefundenen Lücken in der Security-Gruppe systematisch mit echten Tests geschlossen (nicht nur die Schwelle erreicht) — Ist-Stand aktuell 99,4–99,6%/87,5–87,7% (kleine Messwert-Schwankung zwischen Läufen, siehe Abschnitt 8), beide Werte deutlich über der Schwelle. Vier konstant reproduzierte, dokumentierte Zeilen bleiben offen: zwei echter Dead-Code, zwei wegen eines externen Vault-Rate-Limits
Rate-Limit-Backoff der Vault-E-Mail-Hash-MigrationImplementiert (2026-09-26) — Self-Throttle + Retry mit exponentiellem Backoff gegen Vaults Transit-Rate-Limit (60/60s), zuvor gänzlich unbewusst. Vollständig getestet über eine injizierbare Testnaht, ohne das reale Rate-Limit-Budget zu belasten
Mutation-Testing (Voter-Klassen + ChapterContentSanitizer)Implementiert (2026-09-26) — monatlicher Reporting-Cron (Infection), kein CI-Gate. Erster echter Lauf: 596/773 Mutanten getötet, Covered Code MSI 77%
/.well-known/security.txt + Vulnerability Disclosure Policy (Safe Harbor)Implementiert (2026-09-29) — echte Kontaktadresse, dedizierte Policy-Seite
Malware-Scan für JSON-Import-ZIP-InhalteBewusst außen vor — eigener Zip-Bomb-Schutz vorhanden
Dedizierter Produktivserver (aktuell: geteilter Strato-Host für Beta)Hetzner-Umzug geplant, noch nicht live
Unabhängiger externer PenetrationstestNoch nicht stattgefunden
Zertifizierung des Hosters (ISO 27001 o. ä.)Nur implizit über EU-Standort-Entscheidung

Einordnung

  1. Systematisch alle branchenüblichen Maßnahmen sind umgesetzt und mit automatisierten Tests abgesichert — das trägt diese Übersicht.
  2. Ein unabhängiger externer Pentest kann nur von einer tatsächlich durchgeführten Prüfung geliefert werden — kein internes Dokument, egal wie gründlich, kann das ersetzen. Das ist der nächste sinnvolle Schritt vor einem breiteren Onboarding.