Skip to content

fix(security): comprehensive security hardening#2

Open
juliendoclot wants to merge 7 commits intoPAPAMICA:mainfrom
juliendoclot:fix/security-hardening
Open

fix(security): comprehensive security hardening#2
juliendoclot wants to merge 7 commits intoPAPAMICA:mainfrom
juliendoclot:fix/security-hardening

Conversation

@juliendoclot
Copy link
Copy Markdown

Summary

Security audit and hardening of waf-checker addressing critical vulnerabilities:

  • SSRF Protection: Block requests to private IPs (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), cloud metadata endpoints (169.254.169.254), reserved hostnames (localhost, *.local, *.internal), and non-HTTP protocols. Applied to all 10 external-fetch endpoints.
  • Rate Limiting on ALL endpoints: Previously only /api/v1/* was rate-limited. Now all /api/* endpoints have per-endpoint limits (e.g., check=10/min, batch=3/min, recon=5/min). Deterministic cleanup replaces probabilistic Math.random() approach.
  • Remove exposed account_id: Cloudflare account_id was hardcoded in wrangler.toml — replaced with env var instruction.
  • XSS in HTML reports: All user-controlled data (session.url, wafDetection.wafType, evidence[], result.payload, vuln.category, recommendations[]) is now escaped with escapeHtml() before HTML insertion.
  • Batch job security: Guessable job IDs (Date.now + Math.random) replaced with crypto.randomUUID(). IP-based ownership prevents cross-user job access (403). Max 50 jobs total, 3 per IP. Retention reduced from 24h to 1h.
  • Security headers: CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy added to HTML responses.
  • Input validation: Custom headers validated against CRLF injection (rejects \r\n\0), limited to 20 per request. Custom payloads capped at 500. Streaming test requests capped at 10,000.
  • Safe host header placeholder: Replaced hardcoded evil.com (a real registered domain) with waf-test.invalid (RFC 6761 reserved TLD).

New file

  • app/src/security.ts — Centralized security utilities (SSRF validation, RateLimiter class, escapeHtml, header sanitization, security response headers)

Modified files

  • app/src/api.ts — SSRF guards on all handlers, global rate limiting, batch hardening, input validation caps
  • app/src/reporting.ts — XSS escaping in HTML report generation
  • app/src/http-manipulation.ts — Safe host header placeholder
  • app/wrangler.toml — Remove exposed account_id

Test plan

  • http://127.0.0.1, http://169.254.169.254, http://localhost → 400 on all endpoints
  • N+1 requests on /api/check within 60s → 429
  • HTML report with <script>alert(1)</script> in URL → escaped in output
  • Batch job access from different IP → 403
  • Custom header with \r\n → silently rejected
  • HTML response includes CSP, X-Frame-Options headers
  • wrangler.toml contains no account_id
  • Streaming with all options enabled → capped at 10,000 requests
  • evil.com no longer appears in codebase
  • npx tsc --noEmit passes for modified files (pre-existing errors in batch.ts/http-manipulation.ts unchanged)

🤖 Generated with Claude Code

Vercel and others added 7 commits March 25, 2026 11:26
The Cloudflare account_id was hardcoded in the public repository.
Replace with a comment instructing to use env var or CLI flag instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add centralized security module with:
- SSRF protection: private IP detection, reserved hostname blocking,
  sync and async URL validation (with DNS resolution via Cloudflare DoH)
- Rate limiter: per-endpoint configurable limits with deterministic cleanup
- HTML escaping: prevent XSS in server-generated HTML
- Header sanitization: reject CRLF injection in custom headers
- Security response headers: CSP, X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, Permissions-Policy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add URL validation via quickValidateURL() to block requests to:
- Private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Cloud metadata endpoints (169.254.169.254)
- Reserved hostnames (localhost, *.local, *.internal)
- Non-HTTP protocols
- Numeric/hex IP obfuscation

Protected endpoints: /api/check, /api/check-stream, /api/waf-detect,
/api/http-manipulation, /api/security-headers, /api/dns-recon,
/api/recon, /api/speedtest, /api/seo

Also removes the weak 'secmy' domain filter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ty headers

- Replace per-IP in-memory rate limiter with per-endpoint RateLimiter class
  with deterministic cleanup (replaces probabilistic Math.random() cleanup)
- Add global rate limit guard for ALL /api/* endpoints (previously only /api/v1/)
- Per-endpoint limits: check=10/min, stream=5/min, batch=3/min, recon=5/min, etc.
- Add security headers to HTML responses: CSP, X-Content-Type-Options,
  X-Frame-Options, Referrer-Policy, Permissions-Policy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
reporting.ts:
- Add escapeHtml() to all user-controlled data in HTML reports:
  session.url, wafDetection.wafType, evidence[], vuln.category,
  recommendations[], result.payload
- Prevents XSS when opening generated HTML reports in browsers

api.ts batch security:
- Replace guessable job IDs (Date.now + Math.random) with crypto.randomUUID()
- Add IP-based job ownership: only the creator can query/stop a job (403 otherwise)
- Cap max 50 total jobs, 3 concurrent per IP
- Reduce job retention from 24h to 1h
- Apply SSRF validation to batch URLs via quickValidateURL()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…older

api.ts:
- Replace local processCustomHeaders() with sanitizeCustomHeaders() from
  security module (rejects CRLF injection, limits to 20 headers)
- Cap custom payloads to 500 total to prevent memory exhaustion
- Cap streaming test requests to 10,000 max (prevents OOM with all
  encoding variations × methods × categories enabled)

http-manipulation.ts:
- Replace hardcoded 'evil.com' with 'waf-test.invalid' (RFC 6761
  reserved TLD that is guaranteed to never resolve)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant