Pentest R120: Audit-Log /:id mit nicht-numerischer ID → 400 statt 500

Beim Suchen eines verify-integrity-Endpoints stiess der Pentester
auf einen 500er: GET /api/audit-logs/verify matcht GET /:id (das
echte Verify ist POST /verify), parseInt("verify") = NaN → Prisma
findUnique({ where:{ id: NaN }}) wirft. Gleiche 400-statt-500-
Klasse wie R64.1/R104.1.

Fix: Number.isNaN-Guard in getAuditLogById, getAuditLogsByCustomer
und updateRetentionPolicy → sauberer 400 „Ungültige ID".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 23:00:28 +02:00
co-authored by Claude Opus 4.7
parent 42705145dd
commit 094887f1d3
2 changed files with 21 additions and 0 deletions
@@ -54,6 +54,12 @@ export async function getAuditLogs(req: AuthRequest, res: Response) {
export async function getAuditLogById(req: AuthRequest, res: Response) { export async function getAuditLogById(req: AuthRequest, res: Response) {
try { try {
const id = parseInt(req.params.id); const id = parseInt(req.params.id);
// Nicht-numerische :id (z.B. GET /audit-logs/verify statt POST /verify)
// landete sonst als NaN in Prisma findUnique → 500. Sauberer 400.
// (Pentest R120 gleiche „400 statt 500"-Klasse wie R64.1/R104.1.)
if (Number.isNaN(id)) {
return res.status(400).json({ success: false, error: 'Ungültige Audit-Log-ID' });
}
const log = await auditService.getAuditLogById(id); const log = await auditService.getAuditLogById(id);
if (!log) { if (!log) {
@@ -73,6 +79,9 @@ export async function getAuditLogById(req: AuthRequest, res: Response) {
export async function getAuditLogsByCustomer(req: AuthRequest, res: Response) { export async function getAuditLogsByCustomer(req: AuthRequest, res: Response) {
try { try {
const customerId = parseInt(req.params.customerId); const customerId = parseInt(req.params.customerId);
if (Number.isNaN(customerId)) {
return res.status(400).json({ success: false, error: 'Ungültige Kunden-ID' });
}
const logs = await auditService.getAuditLogsByDataSubject(customerId); const logs = await auditService.getAuditLogsByDataSubject(customerId);
res.json({ success: true, data: logs }); res.json({ success: true, data: logs });
@@ -187,6 +196,9 @@ export async function getRetentionPolicies(req: AuthRequest, res: Response) {
export async function updateRetentionPolicy(req: AuthRequest, res: Response) { export async function updateRetentionPolicy(req: AuthRequest, res: Response) {
try { try {
const id = parseInt(req.params.id); const id = parseInt(req.params.id);
if (Number.isNaN(id)) {
return res.status(400).json({ success: false, error: 'Ungültige Policy-ID' });
}
const { retentionDays, description, legalBasis, isActive } = req.body; const { retentionDays, description, legalBasis, isActive } = req.body;
const policy = await auditService.updateRetentionPolicy(id, { const policy = await auditService.updateRetentionPolicy(id, {
+9
View File
@@ -97,6 +97,15 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
## ✅ Erledigt ## ✅ Erledigt
- [x] **🔧 Pentest R120 Audit-Log `/:id` mit nicht-numerischer ID → 500 statt 400**
- Pentester stiess beim Suchen eines `verify-integrity`-Endpoints auf
einen 500er. Ursache: `GET /api/audit-logs/verify` matcht `GET /:id`
(das echte Verify ist `POST /verify`), `parseInt("verify")` = NaN →
Prisma `findUnique({ where:{ id: NaN }})` wirft → 500. Gleiche
„400 statt 500"-Klasse wie R64.1/R104.1.
- Fix: `Number.isNaN`-Guard in `getAuditLogById`,
`getAuditLogsByCustomer` und `updateRetentionPolicy` → sauberer 400.
- [x] **🔴 Pentest R120 CRITICAL IDOR: Vertragsbaum fremder Kunden lesbar** - [x] **🔴 Pentest R120 CRITICAL IDOR: Vertragsbaum fremder Kunden lesbar**
- `GET /api/contracts?tree=true&customerId=<fremd>` returnte für - `GET /api/contracts?tree=true&customerId=<fremd>` returnte für
Portal-User den vollständigen Vertragsbaum eines beliebigen Portal-User den vollständigen Vertragsbaum eines beliebigen