Skip to content

feat: implement production CSP with per-request nonces (closes #93) - #137

Merged
BarryArinze merged 2 commits into
aid-linkk:masterfrom
rindicomfort:feat/implement-csp-with-nonces-93
Aug 27, 2026
Merged

feat: implement production CSP with per-request nonces (closes #93)#137
BarryArinze merged 2 commits into
aid-linkk:masterfrom
rindicomfort:feat/implement-csp-with-nonces-93

Conversation

@rindicomfort

@rindicomfort rindicomfort commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Implement Production CSP with Per-Request Nonces

Closes #93

Summary

This PR implements a production-grade Content Security Policy (CSP) for AidLink with per-request cryptographic nonces, strict-dynamic delegation, comprehensive Stellar network endpoint allowlisting, and a rate-limited violation reporting endpoint.

Implementation Overview

🔒 Security Features

  1. Per-Request Nonce Generation

    • Uses crypto.getRandomValues() with 16 random bytes
    • Unique nonce for every request (prevents replay attacks)
    • Base64-encoded for CSP header compatibility
  2. Production CSP Enforcement

    • Enforces CSP in production (Content-Security-Policy)
    • Report-only in development to support HMR (Content-Security-Policy-Report-Only)
    • Prevents XSS attacks on user-controlled content and on-chain data
  3. Strict Dynamic Script Loading

    • script-src 'nonce-{nonce}' 'strict-dynamic' 'unsafe-eval'
    • Nonce'd scripts can load child scripts without additional nonces
    • No 'unsafe-inline' in script-src (critical for XSS prevention)
    • 'unsafe-eval' required by Stellar SDK for RPC response parsing
  4. Stellar Network Allowlisting

    • Complete coverage of Horizon API (mainnet, testnet, futurenet)
    • Soroban RPC endpoints (mainnet, testnet, futurenet)
    • WebSocket support for real-time updates
    • connect-src directive ensures blockchain interactions are safe
  5. CSP Violation Reporting

    • Dedicated endpoint: POST /api/csp-report
    • Zod-based validation (all fields are attacker-controlled)
    • Rate limiting: 100 reports/minute per IP
    • Structured logging for monitoring and SIEM integration
    • Automatic cleanup to prevent memory leaks

📁 Files Changed

New Files

  • src/middleware.ts - Per-request nonce generation and CSP header injection
  • src/app/api/csp-report/route.ts - Violation reporting endpoint with rate limiting
  • src/__tests__/middleware.test.ts - Comprehensive middleware tests
  • src/app/api/csp-report/__tests__/route.test.ts - API route tests
  • docs/CSP_IMPLEMENTATION.md - Complete implementation documentation
  • CSP_VERIFICATION_GUIDE.md - Step-by-step verification checklist

Modified Files

  • src/app/layout.tsx - Thread nonce from middleware to layout via headers

🎯 CSP Directives Explained

Directive Value Justification
default-src 'self' Only same-origin resources by default
script-src 'nonce-X' 'strict-dynamic' 'unsafe-eval' Nonce for Next.js hydration; strict-dynamic for bundled chunks; unsafe-eval for Stellar SDK
style-src 'self' 'unsafe-inline' Required for Recharts & Framer Motion inline styles (safe - styles can't execute JS)
img-src 'self' data: blob: https: Allow images from various sources
font-src 'self' Only same-origin fonts
connect-src [see below] Allowlist for API and Stellar endpoints
frame-src 'none' No iframes (clickjacking defense)
object-src 'none' No plugins (Flash, Java, etc.)
base-uri 'self' Prevent base tag hijacking
form-action 'self' Forms only submit to same origin
upgrade-insecure-requests - Force HTTP→HTTPS upgrade
report-uri /api/csp-report Send violations to our endpoint

Stellar Endpoints in connect-src:

  • https://horizon.stellar.org (Mainnet Horizon)
  • https://horizon-testnet.stellar.org (Testnet Horizon)
  • https://horizon-futurenet.stellar.org (Futurenet Horizon)
  • https://rpc.mainnet.stellar.org (Mainnet Soroban RPC)
  • https://soroban-testnet.stellar.org (Testnet Soroban RPC)
  • https://rpc-futurenet.stellar.org (Futurenet Soroban RPC)
  • wss://horizon.stellar.org (Mainnet WebSocket)
  • wss://horizon-testnet.stellar.org (Testnet WebSocket)
  • wss://horizon-futurenet.stellar.org (Futurenet WebSocket)

🧪 Test Coverage

Middleware Tests (7 test cases)

  • ✅ Nonce uniqueness across requests
  • ✅ Crypto API usage verification
  • ✅ CSP header in production mode
  • ✅ Report-only header in development
  • ✅ All required directives present
  • ✅ Stellar endpoints included
  • ✅ No 'unsafe-inline' in script-src

API Route Tests (12 test cases)

  • ✅ Valid report acceptance (204)
  • ✅ Content-Type validation
  • ✅ Invalid JSON rejection (400)
  • ✅ Malformed report rejection (400)
  • ✅ Rate limiting (429 on 101st request)
  • ✅ Multiple IP handling
  • ✅ IP extraction from headers
  • ✅ GET request rejection (405)
  • ✅ Minimal report acceptance
  • ✅ application/json support
  • ✅ x-forwarded-for parsing
  • ✅ x-real-ip fallback

✅ Acceptance Criteria Met

All acceptance criteria from issue #93 are satisfied:

  • Per-request nonce uses crypto.getRandomValues() (not Math.random())
  • CSP includes all required directives
  • script-src has nonce- and 'strict-dynamic' but NOT 'unsafe-inline'
  • connect-src has all 6 Stellar HTTP + 3 WSS endpoints
  • Violation endpoint accepts valid reports (204)
  • Violation endpoint rejects invalid reports (400)
  • Rate limiting: 101st request from same IP returns 429
  • Nonce generation: consecutive calls return different values
  • Development mode: CSP is report-only
  • Production mode: CSP is enforced
  • Existing headers (X-Frame-Options, etc.) remain present
  • No 'unsafe-inline' in script-src
  • No 'unsafe-hashes' used
  • Comprehensive test coverage
  • Documentation complete

🔍 Security Considerations

Why 'unsafe-eval'?

The Stellar SDK uses eval() or Function() constructor for parsing RPC responses and dynamic code execution. Testing confirmed this is required - without it, Soroban contract interactions throw EvalError. This is documented in code comments with the specific use case.

Why 'unsafe-inline' in style-src?

Both Recharts (charts) and Framer Motion (animations) inject inline styles via the style attribute. This is safe because:

  1. Inline styles cannot execute JavaScript
  2. CSS injection is less severe than XSS
  3. Alternative (extracting styles) is impractical with these libraries

This tradeoff is explicitly documented and justified.

Rate Limiting Considerations

The in-memory rate limiter is sufficient for basic DoS protection but is not distributed-safe. For production scale:

  • Consider Redis-based rate limiting for multi-instance deployments
  • Leverage CDN-level rate limiting (Cloudflare, etc.)
  • Implement WAF rules for advanced attack detection

Development vs Production

Critical: Never deploy with NODE_ENV=development. This would enable report-only mode, creating a false sense of security. The CSP would log violations but not block them, defeating the purpose.

📊 Attack Surface Reduction

This CSP implementation mitigates the following attack vectors:

  1. Stored XSS - Campaign descriptions, user profiles, on-chain data
  2. DOM-based XSS - Client-side template injection, unsafe DOM manipulation
  3. Script injection - Malicious inline scripts, external script loading
  4. Data exfiltration - Unauthorized API calls, wallet state theft
  5. Clickjacking - frame-src 'none' prevents iframe embedding
  6. Base tag hijacking - base-uri 'self' prevents relative URL manipulation
  7. Form hijacking - form-action 'self' prevents form submission to attacker sites

🚀 Deployment Notes

  1. Build verification: Run npm run build to ensure production build succeeds
  2. Header inspection: Verify CSP header is present and correct with curl -I
  3. Browser testing: Check for CSP violations in production mode
  4. Monitoring: Ingest violation logs into your monitoring system
  5. Gradual rollout: Consider canary deployment to detect unexpected violations

📖 Documentation

  • Implementation Guide: docs/CSP_IMPLEMENTATION.md - Complete technical documentation with directive justifications, security considerations, and references
  • Verification Guide: CSP_VERIFICATION_GUIDE.md - Step-by-step testing procedures, troubleshooting, and acceptance criteria checklist

🔗 References

🧑‍💻 Testing Instructions

# Install dependencies
npm install

# Run tests
npm test

# Type checking
npm run type-check

# Build for production
npm run build

# Start production server
npm run start

# Verify CSP header
curl -I http://localhost:3000

# Test violation reporting
curl -X POST http://localhost:3000/api/csp-report \
  -H "Content-Type: application/csp-report" \
  -d '{"csp-report":{"violated-directive":"script-src"}}'

Detailed verification steps in CSP_VERIFICATION_GUIDE.md.

…reporting

Implements issue aid-linkk#93 - Content Security Policy with the following features:

- Per-request nonce generation using crypto.getRandomValues()
- Production CSP enforcement with strict-dynamic
- Development CSP report-only mode to support HMR
- Complete Stellar network endpoint allowlist (Horizon + Soroban RPC)
- CSP violation reporting endpoint with rate limiting
- Comprehensive test coverage

Security directives implemented:
- script-src: nonce-based with strict-dynamic, unsafe-eval for Stellar SDK
- style-src: unsafe-inline required for Recharts and Framer Motion
- connect-src: all Stellar mainnet/testnet/futurenet endpoints
- frame-src, object-src: none (defense in depth)
- upgrade-insecure-requests: force HTTPS

Rate limiting:
- 100 reports per minute per IP address
- In-memory sliding window counter
- Automatic cleanup to prevent memory leaks

Tests:
- Middleware: nonce uniqueness, CSP construction, environment handling
- API route: validation, rate limiting, error handling

Documentation:
- Complete implementation guide in docs/CSP_IMPLEMENTATION.md
- Verification checklist in CSP_VERIFICATION_GUIDE.md

Closes aid-linkk#93
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants