Pentest 62.7 LOW: deliveryDate / confirmationDate ISO-8601-Validierung
Bisher gingen XSS-Payloads in deliveryDate (saveEmailAsContractDocument, saveAttachmentAsContractDocument, uploadContractDocument) und confirmationDate (Cancellation-Confirmation-Upload) mit 200 durch. Das Datum wurde silent als null behandelt; Impact gering, aber schlechte API-Hygiene. Neuer validateOptionalIsoDate-Helper in utils/sanitize: - ISO-8601-Regex YYYY-MM-DD oder YYYY-MM-DDTHH:MM:SS(.fff)?(Z|+HH:MM)? - null / leerer String / undefined sind OK (Optional-Semantik) - Sonstige Eingaben werfen 400 mit klarer Meldung Eingesetzt in: - contract.controller uploadContractDocument (multer-Datei wird bei Reject sauber gelöscht) - cachedEmail.controller saveEmailAsContractDocument + saveAttachmentAsContractDocument: Validierung früh, BEVOR Dateien geschrieben werden – kein Datei-Müll bei Reject - upload.routes handleContractDocumentUpload (cancellationConfirmation*) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -246,6 +246,33 @@ export function sanitizePhoneField(raw: unknown, fieldLabel: string): string | u
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
// Pentest 62.7 (LOW, 2026-06-02): deliveryDate/confirmationDate-Felder
|
||||
// liefen ungeprüft in maybeActivateOnDeliveryConfirmation. XSS-Payloads
|
||||
// gingen mit 200 durch, weil das ungültige Datum nur silent als null
|
||||
// behandelt wurde. Impact gering, aber API-Hygiene: ungültige Eingabe
|
||||
// soll 400 zurückgeben, nicht 200.
|
||||
//
|
||||
// Akzeptiert: ISO-8601-Datum (YYYY-MM-DD) und Datum+Zeit (mit oder ohne
|
||||
// Zeitzone). Whitespace wird getrimmt. null / leerer String / undefined
|
||||
// sind OK – der Aufrufer behandelt das als "Datum nicht gesetzt".
|
||||
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
|
||||
export function validateOptionalIsoDate(raw: unknown, fieldLabel: string): string | null {
|
||||
if (raw == null) return null;
|
||||
if (typeof raw !== 'string') {
|
||||
throw new Error(`${fieldLabel} muss ein Datums-String (YYYY-MM-DD) sein.`);
|
||||
}
|
||||
const trimmed = raw.trim();
|
||||
if (trimmed === '') return null;
|
||||
if (!ISO_DATE_REGEX.test(trimmed)) {
|
||||
throw new Error(`${fieldLabel} muss ISO-8601-Format haben (YYYY-MM-DD oder YYYY-MM-DDTHH:MM:SS).`);
|
||||
}
|
||||
const parsed = new Date(trimmed);
|
||||
if (isNaN(parsed.getTime())) {
|
||||
throw new Error(`${fieldLabel} ist kein gültiges Datum.`);
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
const NOTES_DEFAULT_MAX = 2000;
|
||||
export function sanitizeNotes(raw: unknown, maxLength: number = NOTES_DEFAULT_MAX): string | null {
|
||||
if (raw == null) return null;
|
||||
|
||||
Reference in New Issue
Block a user