From 8e48d3b432776943e1b81f99b9ff41996b889cb2 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Wed, 20 May 2026 07:49:06 +0200 Subject: [PATCH] Pentest 2026-05-20 LOW/INFO Sammelfix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 27.1 Path-Traversal-Strings in DB: - cleanupConsents validierte documentPath zuvor nur per stripHtml, ließ "../../../etc/passwd" durch. Neuer isValidDocumentPath-Check akzeptiert nur "/uploads/", alles andere → NULL. - cleanupDocumentPaths scannt fünf weitere Tabellen (BankCard, IdentityDocument, Invoice, RepresentativeAuthorization nullable; ContractDocument NOT NULL → nur Report). Orphaned User: - reportOrphanedUsers warnt beim Container-Start vor User ohne Rollenzuordnung (im Permission-System unsichtbar). Löschen nicht automatisch wegen False-Positive-Risiko. Seed-PW-Policy: - generateInitialPassword() nutzte Math.random() (vorhersagbar). Jetzt crypto.randomInt() für Pick + Fisher-Yates-Shuffle. PUT /users/:id mit permissions / password: - Vorher silent-drop durch Whitelist + HTTP 200, Caller glaubte faelschlich, Werte waeren uebernommen. Jetzt HTTP 400 mit konkreter Hilfe-Message. /api/health ohne Auth: - Pentest-Befund INFO: bewusst so, Container-Healthcheck und Reverse-Proxy pingen ohne Bearer-Token. Antwort liefert nur {status,timestamp} – keine Version, kein DB-Status, kein Info-Leak. Comment im Code dokumentiert die Entscheidung. Live-verifiziert auf dev: alle fuenf Findings durchgetestet, jeweils mit dirty Input → erwartete Sanitization/Antwort. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../prisma/cleanup-xss-and-mass-assignment.ts | 119 +++++++++++++++++- backend/prisma/seed.ts | 8 +- backend/src/controllers/user.controller.ts | 28 ++++- backend/src/index.ts | 9 +- docs/todo.md | 33 +++++ 5 files changed, 184 insertions(+), 13 deletions(-) diff --git a/backend/prisma/cleanup-xss-and-mass-assignment.ts b/backend/prisma/cleanup-xss-and-mass-assignment.ts index 2b7ad8ef..d369285b 100644 --- a/backend/prisma/cleanup-xss-and-mass-assignment.ts +++ b/backend/prisma/cleanup-xss-and-mass-assignment.ts @@ -92,11 +92,26 @@ const ALLOWED_CONSENT_SOURCES = new Set([ 'crm-backend', ]); +// Legitimer documentPath: relativer Pfad unter uploads/, keine ".."-Segmente. +// Schreibend werden Pfade ausschließlich vom multer-Upload erzeugt +// (server-kontrollierter Dateiname), bestehende Pentest-Hinterlassenschaften +// wie "../../../etc/passwd" oder "javascript:alert(1)" müssen aus der DB +// raus (Pentest 2026-05-20 LOW 27.1). +function isValidDocumentPath(v: string | null | undefined): boolean { + if (!v) return true; // null/leer ist OK + if (v.includes('..')) return false; + if (/(?:javascript|data|vbscript)\s*:/i.test(v)) return false; + if (/<[a-z!\/]/i.test(v)) return false; // HTML im Pfad + // erlaubt: "uploads/...", "/uploads/..."; keine Kontrollzeichen + return /^\/?uploads\/[A-Za-z0-9._\-\/]+$/.test(v); +} + async function cleanupConsents() { // version + documentPath: HTML strippen (waren ohne Validierung). // source: Whitelist erzwingen. + // documentPath zusätzlich gegen Pfad-Traversal absichern (27.1). let versionStripped = 0; - let pathStripped = 0; + let pathNulled = 0; let sourceFixed = 0; const consents = await prisma.customerConsent.findMany({ select: { id: true, source: true, documentPath: true, version: true }, @@ -107,9 +122,11 @@ async function cleanupConsents() { data.version = stripHtmlString(c.version); versionStripped++; } - if (c.documentPath && c.documentPath !== stripHtmlString(c.documentPath)) { - data.documentPath = stripHtmlString(c.documentPath); - pathStripped++; + if (c.documentPath && !isValidDocumentPath(c.documentPath)) { + // ".../etc/passwd", "