Self-hosted fonts: no fonts.googleapis.com or fonts.gstatic.com. Static assets (including woff2) are served from 'self'.
Adjust report-uri if your API base path or host differs (UAT example below; PROD uses https://pnsps.gld.gov.hk/api/csp-report).
See also: csp-report-review-2026-08-03.md for the PROD report analysis that drove frame-src / media-src updates.
Header always set Content-Security-Policy "default-src 'self'; \
base-uri 'self'; \
object-src 'none'; \
frame-ancestors 'none'; \
form-action 'self'; \
frame-src 'self' data: blob:; \
script-src 'self'; \
style-src 'self' 'unsafe-inline'; \
style-src-elem 'self' 'unsafe-inline'; \
img-src 'self' data: https://www.w3.org https://w3.org; \
media-src 'self' blob: data:; \
font-src 'self' data:; \
connect-src 'self'; \
upgrade-insecure-requests"
Same policy plus violation reporting:
Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
base-uri 'self'; \
object-src 'none'; \
frame-ancestors 'none'; \
form-action 'self'; \
frame-src 'self' data: blob:; \
script-src 'self'; \
style-src 'self' 'unsafe-inline'; \
style-src-elem 'self' 'unsafe-inline'; \
img-src 'self' data: https://www.w3.org https://w3.org; \
media-src 'self' blob: data:; \
font-src 'self' data:; \
connect-src 'self'; \
upgrade-insecure-requests; \
report-uri https://pnspsuat.gld.gov.hk/api/csp-report"
frame-src: Required for proof file preview iframes that use data: / blob: URLs (UploadFileTable.js). Without this, framing falls back to default-src 'self' and browsers report frame-src violations (often with empty blocked-uri).style-src-elem: Explicit, alongside style-src, for <link rel="stylesheet"> behaviour in modern browsers.img-src: Includes https://www.w3.org and https://w3.org so W3C WCAG badge URLs are allowed.media-src: blob: for captcha audio object URLs; data: for data-URI media if used.font-src: 'self' data: covers bundled fonts and data: URLs if used.wasm-eval from chrome-extension) will still appear under Report-Only. Do not allowlist those origins.