From c013e1e747ea146a12ec82fab639274c59e95e1f Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 21 Jun 2026 14:54:15 +0200 Subject: [PATCH] Pentest R93: Leerer String != fehlender Query-Param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R93.1 INFO: ?accountId= (explizit-leer) wurde wie ?accountId weggelassen behandelt → 200 statt 400 auf optionalen Endpunkten. Pentester-Spec: leerer String ist keine gültige Zahl. Fix in parsePositiveIntQuery: nur `v === undefined` ist absent; '', ' ', alles andere muss parsen. Required + optional Modes unverändert. Sanity-Test: alle 11 Cases grün. Co-Authored-By: Claude Opus 4.7 --- .../src/controllers/cachedEmail.controller.ts | 19 ++++++++++++++++--- docs/todo.md | 10 ++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/backend/src/controllers/cachedEmail.controller.ts b/backend/src/controllers/cachedEmail.controller.ts index 5738758f..ff6ca935 100644 --- a/backend/src/controllers/cachedEmail.controller.ts +++ b/backend/src/controllers/cachedEmail.controller.ts @@ -64,8 +64,13 @@ function parsePositiveIntQuery( res: Response, options?: { required?: boolean }, ): number | undefined | null { - const absent = v === undefined || v === '' || (typeof v === 'string' && v.trim() === ''); - if (absent) { + // Pentest 93.1 (INFO, 2026-06-21): `?accountId=` (explizit-leer) wurde + // wie `?accountId` weggelassen behandelt → 200 statt 400 auf optionalen + // Endpunkten. Spec sagt aber: leerer String ist KEINE gültige Zahl. + // Trennung jetzt strikt: + // - Param fehlt komplett (`undefined`) → "absent" + // - Param da, aber Wert leer/Whitespace/keine Zahl → invalid → 400 + if (v === undefined) { if (options?.required) { res.status(400).json({ success: false, @@ -82,7 +87,15 @@ function parsePositiveIntQuery( } as ApiResponse); return null; } - const n = parseInt(v, 10); + const trimmed = v.trim(); + if (trimmed === '') { + res.status(400).json({ + success: false, + error: `${fieldLabel} darf nicht leer sein – bitte weglassen oder positive Ganzzahl angeben.`, + } as ApiResponse); + return null; + } + const n = parseInt(trimmed, 10); if (!Number.isFinite(n) || n < 1 || !Number.isInteger(n)) { res.status(400).json({ success: false, diff --git a/docs/todo.md b/docs/todo.md index d72f2a1b..e617da45 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,16 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **🔒 Pentest R93 – Leerer String != fehlender Param** + - R93.1 (INFO): `?accountId=` (explizit-leer) wurde wie `?accountId` + weggelassen behandelt → 200 statt 400 auf optionalen Endpunkten. + Pentester-Spec: leerer String ist KEINE gültige Zahl. + - Fix im `parsePositiveIntQuery()`-Helper: striktere Absent-Logik + (`v === undefined` ist absent; `''`, `' '`, alles andere muss + parsen). Required + optional Modes unverändert. + - Float-Grenzfall (`accountId=5.5` → 5 via `parseInt`) bleibt als + by-design akzeptiert (Pentester-Bestätigung, kein Security-Impact). + - [x] **🔒 Pentest R92 – Strict-400 für accountId auf Vertrags-Endpunkten** - R91-Fix war silent-undefined bei invaliden Werten: `accountId=abc` auf `GET /contracts/:id/emails` ergab "kein Filter" → Mailbox-