diff --git a/docs/csp-apache.conf.md b/docs/csp-apache.conf.md
index b712a4b7..c7d578e7 100644
--- a/docs/csp-apache.conf.md
+++ b/docs/csp-apache.conf.md
@@ -4,7 +4,10 @@ Self-hosted fonts: no `fonts.googleapis.com` or `fonts.gstatic.com`. Static asse
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](./csp-report-review-2026-08-03.md) for the PROD report analysis that drove `frame-src` / `media-src` updates.
+See also:
+
+- [csp-report-review-2026-08-14.md](./csp-report-review-2026-08-14.md) — latest PROD + UAT report review and add/remove summary
+- [csp-report-review-2026-08-03.md](./csp-report-review-2026-08-03.md) — earlier PROD report analysis that drove `frame-src` / `media-src` updates
## Enforcing
@@ -18,7 +21,7 @@ Header always set Content-Security-Policy "default-src '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; \
+ img-src 'self' data:; \
media-src 'self' blob: data:; \
font-src 'self' data:; \
connect-src 'self'; \
@@ -39,7 +42,7 @@ Header always set Content-Security-Policy-Report-Only "default-src '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; \
+ img-src 'self' data:; \
media-src 'self' blob: data:; \
font-src 'self' data:; \
connect-src 'self'; \
@@ -51,7 +54,7 @@ Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
- **`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 `` behaviour in modern browsers.
-- **`img-src`**: Includes `https://www.w3.org` and `https://w3.org` so W3C WCAG badge URLs are allowed.
+- **`img-src`**: `'self' data:` is enough. The WCAG 2 AA badge is bundled locally (`src/assets/images/wcag2AA.png`) and no longer loaded from `www.w3.org`.
- **`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.
- **Report noise**: Browser extensions (Kaspersky, Perplexity, Youdao, Quark, Google Fonts injected by tooling, `wasm-eval` from chrome-extension) will still appear under Report-Only. Do **not** allowlist those origins.
diff --git a/docs/csp-report-review-2026-08-03.md b/docs/csp-report-review-2026-08-03.md
index 1e0aaea6..5200455c 100644
--- a/docs/csp-report-review-2026-08-03.md
+++ b/docs/csp-report-review-2026-08-03.md
@@ -12,6 +12,7 @@ Source logs (external):
Related app docs:
- [csp-apache.conf.md](./csp-apache.conf.md) — Apache header snippets to deploy
+- [csp-report-review-2026-08-14.md](./csp-report-review-2026-08-14.md) — later PROD + UAT review (add/remove summary)
---
diff --git a/docs/csp-report-review-2026-08-14.md b/docs/csp-report-review-2026-08-14.md
new file mode 100644
index 00000000..34cad47f
--- /dev/null
+++ b/docs/csp-report-review-2026-08-14.md
@@ -0,0 +1,212 @@
+# 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 `