| @@ -99,13 +99,19 @@ map $sent_http_content_type $content_security_policy_inline { |
| 99 | ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'"; |
99 | ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'"; |
| 100 | } |
100 | } |
| 101 | |
101 | |
| 102 | # --- Proxied third-party apps ------------------------------------------- |
102 | # --- Proxied third-party app --------------------------------------------- |
| 103 | # These two are shipped REPORT-ONLY (see the *-report-only.conf includes). |
103 | # Shipped Report-Only first, then PROMOTED TO ENFORCING 2026-08-03 after a real |
| 104 | # Both are third-party SPAs whose runtime behaviour cannot be exercised from |
104 | # browser validated it: homepage, VOD playback + seek on two videos, channel |
| 105 | # the shell -- no browser here -- and a wrong directive fails SILENTLY: video |
105 | # page, and a 39-result search were all clean, and every host contacted was |
| 106 | # stops playing, or every article image disappears, with only a console |
106 | # already in the policy (self, pipedapi, pipedproxy, blob:). |
| 107 | # message. Report-Only gives the visibility with zero outage risk. Promote to |
107 | # |
| 108 | # enforcing after checking a real browser console. |
108 | # The check was proven meaningful before being believed: a deliberately |
| |
109 | # disallowed image was injected and fired a securitypolicyviolation with |
| |
110 | # disposition "report", confirming the header was live rather than absent. |
| |
111 | # |
| |
112 | # (A FreshRSS policy lived here too. It was removed -- rss.krz.sh is routed |
| |
113 | # tunnel-direct to the container and never transits nginx, so the header never |
| |
114 | # reached a browser. FreshRSS enforces its own, correctly RSS-aware, CSP.) |
| 109 | |
115 | |
| 110 | # piped.krz.sh. Derived from evidence, not guesswork: |
116 | # piped.krz.sh. Derived from evidence, not guesswork: |
| 111 | # - connect-src: BACKEND_HOSTNAME=pipedapi.krz.sh (container env). |
117 | # - connect-src: BACKEND_HOSTNAME=pipedapi.krz.sh (container env). |
| @@ -121,15 +127,6 @@ map $sent_http_content_type $csp_piped { |
| 121 | ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; connect-src 'self' https://pipedapi.krz.sh; img-src 'self' https://pipedproxy.krz.sh data: blob:; media-src 'self' https://pipedproxy.krz.sh blob:; script-src 'self' 'unsafe-inline' data:; style-src 'self' 'unsafe-inline'; worker-src 'self' blob:; font-src 'self' data:; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'"; |
127 | ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; connect-src 'self' https://pipedapi.krz.sh; img-src 'self' https://pipedproxy.krz.sh data: blob:; media-src 'self' https://pipedproxy.krz.sh blob:; script-src 'self' 'unsafe-inline' data:; style-src 'self' 'unsafe-inline'; worker-src 'self' blob:; font-src 'self' data:; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'"; |
| 122 | } |
128 | } |
| 123 | |
129 | |
| 124 | # rss.zerolabs.sh (FreshRSS). Operator-only behind Cloudflare Access, so the |
| |
| 125 | # T5 stake is low; the risk is breakage. An RSS reader renders arbitrary feed |
| |
| 126 | # HTML, so img/media must allow remote hosts or every article image dies. |
| |
| 127 | # That remote fetching is inherent to the app and is controlled by FreshRSS's |
| |
| 128 | # own "load remote images" setting, not by CSP. |
| |
| 129 | map $sent_http_content_type $csp_freshrss { |
| |
| 130 | ~*text/(html|javascript)|application/pdf|xml "default-src 'self'; img-src 'self' https: data:; media-src 'self' https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-src https:; base-uri 'none'; form-action 'self'; frame-ancestors 'self'; object-src 'none'"; |
| |
| 131 | } |
| |
| 132 | |
| |
| 133 | # Permissions-Policy variant for media apps. The shared policy sets |
130 | # Permissions-Policy variant for media apps. The shared policy sets |
| 134 | # `fullscreen=()`, which is exactly why piped.conf excludes basic.conf -- it |
131 | # `fullscreen=()`, which is exactly why piped.conf excludes basic.conf -- it |
| 135 | # would stop videos going fullscreen. This keeps every other restriction and |
132 | # would stop videos going fullscreen. This keeps every other restriction and |