# 02. Fix SSRF via Puppeteer --no-sandbox in report generation meta: id: security-fixes-02 feature: security-fixes priority: P1 depends_on: [] tags: [implementation, tests-required, medium-severity] objective: - Prevent SSRF and local file read in the PDF report generator by sandboxing Puppeteer network access deliverables: - Add request interception in Puppeteer to block dangerous URL schemes (file://, metadata endpoints, internal IPs) - Remove or mitigate the `--no-sandbox` flag where possible - Add tests verifying that blocked URLs are not accessible steps: 1. Examine `generatePDF()` at `web/src/server/services/reports/generator.ts:141-150` and `compileData()` at lines 53-137 2. Add `page.setRequestInterception(true)` before `page.setContent()` to intercept all network requests 3. Implement a request filter that blocks: - `file://` scheme (local file read) - Cloud metadata endpoints (`169.254.169.254`, `metadata.google.internal`, etc.) - Internal IP ranges (`10.x.x.x`, `172.16-31.x.x`, `192.168.x.x`, `127.x.x.x`) - `data:` URIs that could load arbitrary content 4. If `--no-sandbox` is required by the deployment environment (e.g., Docker), document the risk and add a compensating control (Chrome flags, network namespace isolation) 5. Add unit tests for the request interception filter tests: - Unit: Request interception blocks `file://`, `data:`, internal IPs, and cloud metadata endpoints - Unit: Request interception allows legitimate external URLs (CDN assets, fonts, etc.) - Integration: Attempting to load a report with embedded `file:///etc/passwd` does not succeed - Integration: Report generation still produces valid PDFs for legitimate content acceptance_criteria: - Puppeteer page cannot make network requests to blocked URL schemes or internal IPs - `file://` URLs are blocked, preventing local file read - Cloud metadata endpoints are blocked - Report PDFs still render correctly for legitimate content - The `--no-sandbox` flag is either removed or has documented compensating controls validation: - `cd web && bun test` — all tests pass - Attempt to inject a `file:///etc/passwd` URL through report data and verify it is blocked - Verify report generation still produces valid PDFs notes: - Finding p8-002: The `--no-sandbox` flag is likely required in containerized environments; if so, network-level sandboxing via request interception is the compensating control - Consider using `page.setContent(html, {waitUntil: 'networkidle0'})` with interception enabled - The `compileData()` function builds HTML from database data — any user-controlled data in reports could include `` or ``