security: SSRF prevention, ownership gaps, host header injection, date validation
- webhooks: block SSRF — reject localhost/127.x/169.254.x/10.x/192.168.x
URLs at creation and silently skip at dispatch time
- medication-profiles/last-intakes: add family ownership check on babyId
- invite/send-email: build invite URL from NEXTAUTH_URL env only;
drop req.headers.get("origin") to prevent host header injection
- baby POST: validate birthDate is a real date; add required-fields check
- milk POST: validate storedAt before new Date()
- journal GET: validate date filter before new Date()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+47
-3
@@ -11,11 +11,11 @@
|
||||
| Severity | Found | Fixed |
|
||||
|----------|-------|-------|
|
||||
| CRITICAL | 9 | 9 |
|
||||
| HIGH | 11 | 10 |
|
||||
| MEDIUM | 7 | 5 |
|
||||
| HIGH | 13 | 12 |
|
||||
| MEDIUM | 10 | 8 |
|
||||
| LOW | 1 | 0 |
|
||||
|
||||
_Updated after second-pass audit (pass 2 of 2)._
|
||||
_Updated after third-pass audit (pass 3 of 3)._
|
||||
|
||||
---
|
||||
|
||||
@@ -209,6 +209,50 @@ If `SUPERADMIN_EMAIL` env var is not set, the condition `SUPERADMIN_EMAIL && ses
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## HIGH — Fixed (pass 3)
|
||||
|
||||
### 25. SSRF via webhook URL — internal IP/localhost allowed
|
||||
**Affected:** `webhooks/route.ts` POST (creation) and `lib/webhooks.ts` dispatch
|
||||
|
||||
**Problem:** Webhook URLs were accepted without hostname validation. An attacker could register `http://localhost:5432` or `http://169.254.169.254/latest/meta-data/` (AWS metadata endpoint) and cause the server to make requests to internal services, leaking credentials or probing the internal network.
|
||||
|
||||
**Fix:** Added `isSafeWebhookUrl()` helper using regex to reject `localhost`, `127.x`, `0.0.0.0`, `::1`, `10.x`, `172.16–31.x`, `192.168.x`, `169.254.x`. Applied at both creation (returns 400) and dispatch (skips the hook silently).
|
||||
|
||||
---
|
||||
|
||||
### 26. `medication-profiles/last-intakes` — missing family ownership check
|
||||
**Problem:** Accepted any `babyId` without verifying it belongs to the session user's family. Cross-family medication data leak.
|
||||
|
||||
**Fix:** Added `prisma.baby.findFirst({ where: { id: babyId, familyId } })` check.
|
||||
|
||||
---
|
||||
|
||||
## MEDIUM — Fixed (pass 3)
|
||||
|
||||
### 27. Host header injection in invite email URL
|
||||
**Affected:** `invite/send-email/route.ts`
|
||||
|
||||
**Problem:** Used `req.headers.get("origin")` to build the invite URL, allowing an attacker to craft a request with `Origin: https://evil.com` and send phishing links to invited users.
|
||||
|
||||
**Fix:** Now uses `process.env.NEXTAUTH_URL` exclusively; request Origin header ignored.
|
||||
|
||||
---
|
||||
|
||||
### 28. `baby/route.ts` POST — birthDate not validated
|
||||
**Problem:** `new Date(birthDate)` accepted invalid strings silently; also no required-fields check.
|
||||
|
||||
**Fix:** Added `!name || !birthDate` check + `isNaN` date validation.
|
||||
|
||||
---
|
||||
|
||||
### 29. `milk/route.ts` POST — storedAt not validated
|
||||
### 30. `journal/route.ts` GET — date filter not validated
|
||||
**Fix:** Added `isNaN(new Date(x).getTime())` guards on both.
|
||||
|
||||
---
|
||||
|
||||
## MEDIUM — Not applicable (already handled)
|
||||
|
||||
### Upload route — extension from MIME type, not filename
|
||||
|
||||
Reference in New Issue
Block a user