security sweep
This commit is contained in:
50
tasks/security-fixes/02-fix-puppeteer-ssrf-report-gen.md
Normal file
50
tasks/security-fixes/02-fix-puppeteer-ssrf-report-gen.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 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/...">`
|
||||
Reference in New Issue
Block a user