# CSP Report Review (PROD + UAT, 2026-08-14) Review of Content-Security-Policy-Report-Only violations from PNSPS PROD (`https://pnsps.gld.gov.hk`) and UAT (`https://pnspsuat.gld.gov.hk`), for deciding Apache CSP updates. Source logs (external): - `P1 CSP.txt` — PROD node, 168 reports, 2026-07-30 to 2026-08-14 - `P2 CSP.txt` — PROD node, 137 reports, 2026-07-30 to 2026-08-14 - `TT CSP.txt` — UAT, 133 reports, 2026-05-29 to 2026-08-03 Related app docs: - [csp-apache.conf.md](./csp-apache.conf.md) — Apache header snippets to deploy - [csp-report-review-2026-08-03.md](./csp-report-review-2026-08-03.md) — earlier PROD review --- ## Verdict CSP is still **Report-Only** (`disposition: report`) — nothing is blocking users yet. There is **one real PNSPS SPA problem** (proof PDF preview `frame-src`). Everything else is browser-extension noise or a **different app** on the same UAT host. The 2026-08-03 recommendation to add `frame-src` is **still not on the live header**. --- ## Add / remove summary **PROD — add one line, remove nothing:** ```apache frame-src 'self' data: blob:; ``` Keep `script-src 'self'`. Do not add `'unsafe-inline'` or `'unsafe-eval'`. **UAT — add the same line, remove nothing now:** ```apache frame-src 'self' data: blob:; ``` Keep `script-src 'self' 'unsafe-inline' 'unsafe-eval'` for now (JSF payment recon on the same host). Do not copy this `script-src` to PROD. **Do not add on either env:** `'wasm-unsafe-eval'`, Youdao, NetEase CDN, `todesktop-internal`, Google Fonts. **Optional later (not required for these reports):** UAT can drop `'unsafe-inline' 'unsafe-eval'` from the SPA header only after `/paymentrecon-dept_web/` has its own CSP. --- ## Confirmed current PROD policy (Report-Only) This is the live header that generated the P1/P2 reports. It matches the `original-policy` in every PROD violation. ```apache Header always set Content-Security-Policy-Report-Only "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" ``` Gap vs the reports: **no `frame-src`**. Framing therefore falls back to `default-src 'self'`, which is why proof PDF preview reports `frame-src` with an empty `blocked-uri`. --- ## Confirmed current UAT policy (Report-Only) ```apache Header always set Content-Security-Policy-Report-Only "default-src 'self'; \ base-uri 'self'; \ object-src 'none'; \ frame-ancestors 'none'; \ form-action 'self'; \ script-src 'self' 'unsafe-inline' 'unsafe-eval'; \ 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://pnspsuat.gld.gov.hk/api/csp-report" ``` UAT vs PROD differences: - UAT `script-src` is `'self' 'unsafe-inline' 'unsafe-eval'` — PROD is `'self'` only. - Both still lack `frame-src`. - TT report `original-policy` was older: `script-src 'self' 'unsafe-inline'` **without** `'unsafe-eval'`. That is why TT logged 42 JSF `eval` hits. Those should stop under the current UAT header. Do **not** copy `'unsafe-inline'` or `'unsafe-eval'` onto PROD. The React SPA does not need them. `'unsafe-eval'` is only there for the shared-host JSF payment recon app. --- ## Real problem (PROD P1 + P2) | Volume | Directive | Blocked | Pages | |---:|---|---|---| | 150 | `frame-src` | empty `""` | `/proof/create/{id}` | Source is always `static/js/4608.4af455e6.chunk.js`. Cause is proof file preview in `src/pages/Proof/Create_FromApp/UploadFileTable.js`: `FileReader.readAsDataURL` then `document.write` an `