From 0e0da4bd147c738995915fccf63ef5b511cca10d Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Tue, 3 Mar 2026 18:41:16 +0800 Subject: [PATCH] Fix nginx header inheritance regression and add 0.0.0.0/8 to SSRF blocklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NEW-1: add_header in location /api block suppressed server-level security headers (HSTS, CSP, X-Frame-Options, etc). Duplicate all security headers into the /api block explicitly per nginx inheritance rules. NEW-2: Add 0.0.0.0/8 to _BLOCKED_NETWORKS — on Linux 0.0.0.0 connects to localhost, bypassing the existing loopback check. Co-Authored-By: Claude Opus 4.6 --- backend/app/services/ntfy.py | 3 ++- frontend/nginx.conf | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/app/services/ntfy.py b/backend/app/services/ntfy.py index 3fb4f2b..d1574ab 100644 --- a/backend/app/services/ntfy.py +++ b/backend/app/services/ntfy.py @@ -21,7 +21,8 @@ NTFY_TIMEOUT = 8.0 # seconds — hard cap to prevent hung requests # SSRF against Docker-internal services. If a self-hosted ntfy server on the LAN # is required, remove the RFC 1918 entries from _BLOCKED_NETWORKS and document the accepted risk. _BLOCKED_NETWORKS = [ - ipaddress.ip_network("127.0.0.0/8"), # IPv4 loopback + ipaddress.ip_network("0.0.0.0/8"), # "This network" — 0.0.0.0 maps to localhost on Linux + ipaddress.ip_network("127.0.0.0/8"), # IPv4 loopback ipaddress.ip_network("10.0.0.0/8"), # RFC 1918 private ipaddress.ip_network("172.16.0.0/12"), # RFC 1918 private — covers Docker bridge 172.17-31.x ipaddress.ip_network("192.168.0.0/16"), # RFC 1918 private diff --git a/frontend/nginx.conf b/frontend/nginx.conf index bae1954..17a0f09 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -103,6 +103,14 @@ server { # PT-L01: Prevent browser caching of authenticated API responses add_header Cache-Control "no-store, no-cache, must-revalidate" always; + # Security headers (must be repeated — nginx add_header in a location block + # overrides server-level add_header directives, so all headers must be explicit) + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data:; font-src 'self' https://fonts.gstatic.com; connect-src 'self';" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always; } # SPA fallback - serve index.html for all routes