From a95aa384a23b318f5d7233d5a5792f33d50227db Mon Sep 17 00:00:00 2001 From: duffyduck Date: Wed, 20 May 2026 20:14:59 +0200 Subject: [PATCH] Pentest 2026-05-20 Pen-30-Befunde (MEDIUM+INFO) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 30.13 MIME-Extension-XSS (MEDIUM): GET /api/files/download lieferte hochgeladene Dateien via res.sendFile() aus. Da multer nur den client-gemeldeten MIME prueft, konnte eine als application/pdf deklarierte .html-Datei auf Disk landen – Express liest beim Senden den Content-Type aus der Extension (text/html), Browser haette gerendert → Stored XSS. Fix: Content-Disposition: attachment + safe filename. Browser laedt jetzt herunter statt zu rendern, egal welcher Content-Type. UX-Cost ist gering (PDF-Preview offnet halt aus dem Download-Ordner). X-Content-Type-Options: nosniff bleibt zusaetzlich gesetzt. 30.14 SSRF Private-IP-Block opt-in (INFO): ssrfGuard erlaubte private IPs (127/10/172.16/192.168) bewusst, weil On-Prem-Setups Plesk/Dovecot/Postfix lokal laufen lassen. Fuer Cloud-Deployments ist das ein SSRF-Vektor. Neuer Env-Flag SSRF_BLOCK_PRIVATE_IPS=true erweitert die Block-Liste um alle privaten Ranges + ::1 + fc00::/7 + IPv4-mapped + localhost/ ip6-localhost. Default off (on-prem-kompatibel). Live-verifiziert auf dev: - Download-Header: Content-Disposition: attachment + safe filename - Default: 127.0.0.1/10.x/192.168.x/localhost durchgelassen, 169.254.169.254 (Cloud-Metadata) weiter geblockt - SSRF_BLOCK_PRIVATE_IPS=true: alle privaten Ranges geblockt, 8.8.8.8 (legitim) durchgelassen Co-Authored-By: Claude Opus 4.7 (1M context) --- .../controllers/fileDownload.controller.ts | 16 +++++++++- backend/src/utils/ssrfGuard.ts | 32 +++++++++++++++++++ docs/todo.md | 29 +++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/fileDownload.controller.ts b/backend/src/controllers/fileDownload.controller.ts index eb949931..c5f31975 100644 --- a/backend/src/controllers/fileDownload.controller.ts +++ b/backend/src/controllers/fileDownload.controller.ts @@ -78,7 +78,21 @@ export async function downloadFile(req: AuthRequest, res: Response): Promise` + bestehendes `X-Content-Type- + Options: nosniff`. Browser lädt jetzt herunter statt zu rendern, + selbst wenn der Type stimmt. Filename wird auf + `[A-Za-z0-9._-]` gesäubert. + - **30.14 SSRF Private-IP-Block opt-in** (INFO): Neuer Env-Flag + `SSRF_BLOCK_PRIVATE_IPS=true` erweitert die SSRF-Block-Liste auf + 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1, + fc00::/7 + IPv4-mapped Varianten + Hostnamen "localhost"/ + "ip6-localhost". Default off, damit On-Prem-Installationen + (Plesk/Dovecot auf 127.0.0.1) nicht brechen. Cloud-Deployments + setzen den Flag. + - **Live-verifiziert** auf dev: + - Upload + Download: Header zeigt + `Content-Disposition: attachment; filename="…"` + + `X-Content-Type-Options: nosniff` + - Default-ssrfGuard: 127.0.0.1 / 10.x / 192.168.x / localhost → false + (durchgelassen für on-prem); 169.254.169.254 → true (Cloud- + Metadata weiter geblockt) + - Mit `SSRF_BLOCK_PRIVATE_IPS=true`: alle privaten Ranges → true; + 8.8.8.8 (legit public) → false + - [x] **🛡️ Pentest 2026-05-20 Pen-29-Befunde (LOW/INFO)** - **28.1 Restarbeit**: `DANGEROUS_URI_SCHEMES` jetzt vollständig – `blob:`, `about:`, `ws:`, `wss:`, `ldap:`, `dict:` ergänzt. Bewusst