Review of Content-Security-Policy-Report-Only violations from PNSPS PROD
(https://pnsps.gld.gov.hk), for deciding Apache CSP updates.
Source logs (external):
PNSPS PROD CSP Report 2026-08-03.txtsummary.txtCSP Issue 1.txt (script-src / eval samples)Related app docs:
default-src 'self';
base-uri 'self';
object-src 'none';
frame-ancestors 'none';
form-action 'self';
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:;
font-src 'self' data:;
connect-src 'self';
upgrade-insecure-requests;
report-uri https://pnsps.gld.gov.hk/api/csp-report
Notes:
report (Report-Only); nothing was enforced.frame-src → framing falls back to default-src 'self'.Most reports are browser / extension noise. Only one directive change is
required for app functionality: add frame-src.
| Approx. volume | Directive | Blocked | Verdict |
|---|---|---|---|
| ~3000 | frame-src |
empty / data: (URI often stripped) |
App — PDF preview iframes |
| ~1500 | script-src |
wasm-eval |
Noise — chrome-extension |
| ~1400 | font-src |
fonts.gstatic.com (Inter / Nunito) |
Noise — not app fonts |
| ~500 | img-src |
https://www.w3.org/WAI/wcag2AA |
Already allowed; mostly doc 404 noise |
| ~240 | font-src |
at.alicdn.com, cdn.yiban.io, Perplexity CDN |
Noise — toolbars / extensions |
| ~180 | style-src-elem |
fonts.googleapis.com |
Noise — not loaded by app |
| ~70 | script-src |
eval (line ~67) |
Noise — no app eval |
| rest | various | Kaspersky, Youdao, Quark, todesktop-internal, etc. |
Noise |
App fonts are self-hosted (@fontsource Public Sans / Noto; see public/index.html
and src/assets/fonts.css). Google Fonts (Roboto / Inter / Nunito) are not
part of the app and must not be allowlisted.
frame-srcProof upload preview in
src/pages/Proof/Create_FromApp/UploadFileTable.js:
FileReader.readAsDataURL(...) builds a data: URLwindow.open("") then document.write an <iframe src="data:...">With no frame-src, CSP uses default-src 'self', which blocks data: frames.
Browsers often report blocked-uri as empty ("") for privacy.
Almost all of these hits are on /proof/create/..., source
static/js/4608.*.chunk.js.
frame-src 'self' data: blob:;
Prefer URL.createObjectURL + blob: for preview (still needs frame-src ... blob:).
media-src and data:Small volume of media-src / data on login and related pages.
Captcha audio already uses blob: (CustomFormWizard.js and similar). Adding
data: is low risk:
media-src 'self' blob: data:;
img-src / www.w3.org)AuthFooter.js loads https://www.w3.org/WAI/wcag2AA. Policy already allows
https://www.w3.org and https://w3.org. Many reports had document
status-code: 404 (SPA shell). No Apache change required.
Optional hardening: host the badge image locally.
epaygateway1.gcis.gov.hk)Single style-src-elem hit on /paymentPage/callback with gateway referrer.
Card payment uses window.location.assign(redirecturl), not embedded gateway CSS.
Do not allowlist unless a real UI break is confirmed.
| Requested by reports | Why not |
|---|---|
'unsafe-eval' / 'wasm-unsafe-eval' |
Extension / injected; app has no eval |
fonts.googleapis.com / fonts.gstatic.com |
App uses self-hosted fonts |
Kaspersky (*.kis.v2.scr.kaspersky-labs.com) |
AV injection |
| Perplexity, Youdao, Quark, alicdn, yiban, NetEase CDN | Third-party client tooling |
todesktop-internal |
Desktop wrapper noise |
epaygateway1.gcis.gov.hk (styles) |
Not required for current payment flow |
Use the snippets in csp-apache.conf.md.
Changes vs the 2026-08-03 deployed policy:
frame-src 'self' data: blob:;media-src to 'self' blob: data:;/api/csp-report for a few days — expect frame-src volume to drop;
remaining extension noise is OK.Adjust report-uri host for UAT vs PROD:
https://pnspsuat.gld.gov.hk/api/csp-reporthttps://pnsps.gld.gov.hk/api/csp-reportPOST /csp-report (context path → /api/csp-report)default-src 'self'; script-src 'self'; frame-ancestors 'self').
Frontend/Apache CSP above is what browsers enforce for the SPA document.