Files
Kordant/tasks/security-fixes/02-fix-puppeteer-ssrf-report-gen.md
2026-05-29 09:03:47 -04:00

51 lines
2.7 KiB
Markdown

# 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 `<img src="file://...">` or `<link href="http://169.254.169.254/...">`