Mass-Assignment-Schutz: Contract-Create/Update Feld-Whitelist (R158)

Letzter Spread-Endpunkt: createContract/updateContract reichten rohen
...contractData an Prisma durch (via as any im Controller). customerId ist
zwar legitim aenderbar (Kunden-Select aktiv), aber id/contractNumber/
createdAt/updatedAt/portalPasswordEncrypted und die cancellation*Path-Felder
waren so mit-injizierbar. Jetzt explizite Feld-Whitelist (pickContractScalars),
konsistent zur R156-Haertung von BankCard/Address/Document.

Whitelist autoritativ aus den DB-Spalten abgeleitet - der ContractCreateData-
Typ ist unvollstaendig: previousProviderId/previousContractNumber/
previousCustomerNumber/nextReviewDate sind echte Formularfelder, die sonst
still gebrochen waeren. cancellation*Path bleiben bewusst draussen (nur ueber
die Upload-/Delete-Endpunkte setzbar).

Verifiziert: legit Felder (inkl. der 4 zuvor untypisierten) persistieren;
injizierte id/contractNumber/cancellationLetterPath werden ignoriert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 19:27:25 +02:00
co-authored by Claude Opus 4.8
parent fc3131059b
commit 94e4fdee23
2 changed files with 54 additions and 3 deletions
+15
View File
@@ -97,6 +97,21 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt
- [x] **🔒 Mass-Assignment-Schutz: Contract-Create/Update (Pentest R158-Hygiene)** (2026-08-13)
- Letzter Spread-Endpunkt (`createContract`/`updateContract` spreadeten rohen
`...contractData` an Prisma) auf eine **Feld-Whitelist** umgestellt konsistent
zur R156-Härtung (BankCard/Address/Document). `id`/`contractNumber`/`createdAt`/
`updatedAt`/`portalPasswordEncrypted` und alle `cancellation*Path`-Felder sind
damit **nicht** mehr per Form-Update setzbar (Pfade nur noch über die
Upload-Endpunkte).
- **Whitelist autoritativ aus den DB-Spalten** abgeleitet (nicht aus dem
unvollständigen `ContractCreateData`-Typ!) dabei fielen 4 echte, vom Formular
gesendete Felder auf, die NICHT im Typ standen und sonst still gebrochen wären:
`previousProviderId`, `previousContractNumber`, `previousCustomerNumber`,
`nextReviewDate`.
- Verifiziert: legit Felder (inkl. der 4) persistieren; injizierte
`id`/`contractNumber`/`cancellationLetterPath` werden ignoriert.
- [x] **🗂️ Neuer Vertragsstatus „Gekündigt / bestätigt" + Kündigungs-Workflow** (2026-08-13)
- Bisheriges **„Gekündigt"** umbenannt in **„Gekündigt / Bestätigung abwarten"**
(Status `CANCELLED`) wird jetzt automatisch gesetzt, sobald ein