From b3469483cab5d780f953d2003c9c11564f0c026d Mon Sep 17 00:00:00 2001 From: duffyduck Date: Thu, 18 Jun 2026 15:28:59 +0200 Subject: [PATCH] Pentest 77.3 (LOW): requireIdParam blockt Float-IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Number.isInteger(parseInt('4.5')) ist true, weil parseInt den Nachkomma-Teil silent verwirft. /.../4.5/... traf die echte ID 4 statt 400 zu liefern – gleiches für 4.0 und Exp-Notation (4e1). Fix: vor dem Parsen Regex /^\\d+$/ gegen die rohe Route-Eingabe. Nur reine Ziffern erlaubt, keine Floats / Exp / Vorzeichen / Whitespace / Hex. Smoke-Test (17 Cases): 4.0, 4.5, 4e1, 4E2, 0, -4, +4, 0x10, 1.0e0, leading/trailing Space alle abgelehnt; 1, 4, 100, 9999999 durchgewunken. --- .../src/controllers/stressfreiEmail.controller.ts | 12 ++++++++++-- docs/todo.md | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backend/src/controllers/stressfreiEmail.controller.ts b/backend/src/controllers/stressfreiEmail.controller.ts index 45529040..f7e949f1 100644 --- a/backend/src/controllers/stressfreiEmail.controller.ts +++ b/backend/src/controllers/stressfreiEmail.controller.ts @@ -6,10 +6,18 @@ import { canAccessCustomer, canAccessStressfreiEmail } from '../utils/accessCont import { ApiError } from '../utils/apiError.js'; // Pentest 71.3 (INFO): `parseInt(...)` ohne NaN-Check gab bei -// `/stressfrei-emails/abc/...` einen generischen 500 zurück. Nicht -// kritisch, aber irreführend und log-spammend. +// `/stressfrei-emails/abc/...` einen generischen 500 zurück. +// +// Pentest 77.3 (LOW): `Number.isInteger(parseInt(...))` ließ Floats +// und Exponential-Notation durch – `4.0`, `4.5`, `4e1` werden alle +// zu `4` geparst und treffen die echte ID 4. Fix: erst gegen +// `/^\d+$/` validieren, dann erst parsen. function requireIdParam(req: AuthRequest, res: Response, paramName: string): number | null { const raw = req.params[paramName]; + if (typeof raw !== 'string' || !/^\d+$/.test(raw)) { + res.status(400).json({ success: false, error: `Ungültige ID: ${raw}` } as ApiResponse); + return null; + } const parsed = Number.parseInt(raw, 10); if (!Number.isInteger(parsed) || parsed < 1) { res.status(400).json({ success: false, error: `Ungültige ID: ${raw}` } as ApiResponse); diff --git a/docs/todo.md b/docs/todo.md index 6986c4f8..2f8cb380 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,18 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **🔒 Pentest 77.3 (LOW): `requireIdParam` ließ Float-IDs durch** + - `Number.isInteger(parseInt('4.5'))` ist `true`, weil `parseInt` + den Nachkomma-Teil silent abschneidet. Damit traf `/.../4.5/...` + auf die echte ID 4 statt 400 zurückzuliefern. Gleiches gilt für + `4.0` und Exp-Notation `4e1`. + - Fix: vorm Parsen Regex `/^\d+$/` auf die rohe `req.params.`- + Eingabe. Nur reine Ziffern erlaubt – keine Floats, Exp, Vorzeichen, + Whitespace, Hex. + - Smoke-Test (17 Cases): `4.0`, `4.5`, `4e1`, `4E2`, `0`, `-4`, `+4`, + `0x10`, `1.0e0`, leading/trailing Space alle abgelehnt; `1`, `4`, + `100`, `9999999` durchgewunken. + - [x] **🐞 Stressfrei-Adressen: doppelte E-Mails beim Anlegen erlaubt** - Bug: User konnte dieselbe Adresse zweimal beim selben Kunden anlegen (siehe Screenshot mit 2× `max.mustermann@...`). `createEmail`