Live-Pentest gegen Dev-Server + 3 parallele Audit-Agents.
🚨 CRITICAL: /api/uploads/* war ohne Auth erreichbar
- express.static('/api/uploads', ...) → jeder konnte mit ratbarer URL
sensible PDFs (Kündigungsbestätigungen, Ausweise, Bankkarten,
Vollmachten) ziehen. Live-verifiziert: 23-KB-PDF eines echten Kunden
ohne Login geladen.
- Fix: authenticate-Middleware vor static-Handler (req.query.token
unterstützung war schon da, jetzt aktiv genutzt).
- Frontend: utils/fileUrl.ts hängt JWT als ?token=... an. 24 direkte
/api${...Path}-URLs in 5 Dateien per Skript migriert (CustomerDetail,
ContractDetail, InvoicesSection, PdfTemplates, GDPRDashboard).
🚨 HIGH: Login-Timing User-Enumeration
- bcrypt.compare wurde nur bei existierenden Usern ausgeführt → 110ms
vs 10ms Differenz, Email-Enumeration trivial messbar.
- Fix: Dummy-bcrypt-compare bei invalid user (Cost 12). Plus Lazy-
Rehash bei erfolgreichem Login: alte Cost-10-Hashes (z.B. admin aus
Installation) werden auf BCRYPT_COST upgraded, damit Dummy- und
Echt-Hash-Cost zusammenpassen.
- Live-verifiziert nach Admin-Rehash: 422ms (invalid) vs 423ms (valid)
– Side-Channel dicht.
🚨 HIGH: XSS via Privacy-Policy/Imprint-HTML
- 4 Frontend-Seiten renderten Backend-HTML ohne DOMPurify
(PortalPrivacy, ConsentPage, PortalWebsitePrivacy, PortalImprint).
Admin-eingegebene <script>-Tags wären bei jedem Portal-Kunden-
Besuch ausgeführt worden – auch auf der öffentlichen Consent-Seite.
- Fix: DOMPurify.sanitize mit strikter FORBID_TAGS/ATTR Config.
🛡 HIGH: IDOR-Härtung an Upload-/Document-Endpoints
- canAccessContract jetzt in: uploadContractDocument,
deleteContractDocument, handleContractDocumentUpload (Kündigungs-
Letter+Confirmation), handleContractDocumentDelete,
saveAttachmentAsContractDocument.
- Defense-in-Depth: aktuell durch requirePermission abgesichert,
schützt auch gegen künftige Staff-Scoping-Rollen.
Offen für v1.1:
- Per-File-Ownership-Check für /api/uploads (Kontroll-Lookup
welche Ressource zur Datei gehört)
- TipTap-Link-Tool javascript:-Protokoll blockieren
- Prisma-Error-Messages in Admin-Endpoints generisch sanitisieren
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>