fix(security): SSRF protection for alarm webhooks (FLAW-05)

Discord and custom webhook URLs are checked when saved and before every
call: https only, Discord URLs must point to discord.com. A guarded HTTP
client resolves hosts itself and connects only to allowed IPs; localhost,
link-local and cloud metadata are always blocked, LAN ranges (incl.
Tailscale CGNAT) and plain http only with the new admin switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 07:37:39 +01:00
1 parent 4cdbcbd6b5
commit 62463bc6fd
8 files changed
+288 -16

No files matched your search

+2 -1
View File
@@ -14,7 +14,7 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** (
| FLAW-02 | Realtime | ~~Räume ohne Berechtigungsprüfung~~ | **Behoben** |
| FLAW-03 | Aufgaben | ~~`ReorderTasks` ändert beliebige Aufgaben per ID (IDOR)~~ | **Behoben** |
| FLAW-04 | Auth | ~~Fest eincodiertes Fallback-`JWT_SECRET`~~ | **Behoben** |
| FLAW-05 | Benachrichtigungen | Discord-/Webhook-URLs ungeprüft (SSRF) | Mittel |
| FLAW-05 | Benachrichtigungen | ~~Discord-/Webhook-URLs ungeprüft (SSRF)~~ | **Behoben** |
| FLAW-06 | Aufgaben | ~~Jeder Editor einer Aufgabenliste kann sie per `teamId` an weitere Gruppen freigeben~~ | **Behoben** |
| FLAW-07 | Auth | API-Key-`scopes` werden nie ausgewertet; ein Key ist ein Vollzugriff | Mittel |
| FLAW-08 | Auth | Webhook-Ingest mit JWT prüft weder Sperrliste noch `token_version` noch `is_active` | Mittel |
@@ -66,6 +66,7 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** (
- **Maßnahme:** Start verweigern oder Secret beim ersten Start erzeugen und in `/data` ablegen.
### FLAW-05: SSRF über Alarm-URLs
- **Status: Behoben.** [netguard.go](../internal/api/netguard.go): URLs werden beim Speichern und vor jedem Versand geprüft (https Pflicht, Discord nur `discord.com/api/webhooks/`). Der HTTP-Client löst den Host selbst auf und verbindet nur zu erlaubten IPs: localhost, Link-Local/Cloud-Metadaten sind immer gesperrt, Heimnetz-Bereiche (RFC 1918, ULA, CGNAT/Tailscale) und http nur mit dem Admin-Schalter „Alarm-Webhooks ins lokale Netz erlauben“. Keine Umgebungs-Proxys, höchstens 3 Weiterleitungen.
- **Fundstellen:** `handleUpdateUserSettings` (keine Validierung), `sendDiscordNotification`, `sendCustomWebhookNotification`.
- **Problem:** Jeder Nutzer kann beliebige URLs hinterlegen. Der Server sendet POST-Anfragen dorthin, auch an interne Adressen (`http://169.254.169.254`, Docker-Netz, `localhost`). Über `handleTestUserAlarm` lässt sich das sofort auslösen.
- **Maßnahme:** Nur `https`, Discord-Host prüfen, private/Loopback-Adressen beim Verbinden sperren.