Skip to content

feat: harden application with CSP, security headers, input validation, CSRF protection, and env validation - #35

Merged
KarenZita01 merged 1 commit into
EquipChain:mainfrom
iyanumajekodunmi756:feat/security-hardening
Jul 29, 2026
Merged

feat: harden application with CSP, security headers, input validation, CSRF protection, and env validation#35
KarenZita01 merged 1 commit into
EquipChain:mainfrom
iyanumajekodunmi756:feat/security-hardening

Conversation

@iyanumajekodunmi756

Copy link
Copy Markdown
Contributor

Summary

Implements comprehensive security hardening for the EquipChain frontend as described in issue #25. As a blockchain-connected application handling financial transactions on Stellar Soroban, security is paramount. This PR adds multiple layers of defense: HTTP security headers, CSRF protection, input validation with Zod, input sanitization, environment variable validation, transaction simulation, and dependency auditing in CI.

Closes #25


Changes

🔒 Security Headers (src/middleware.ts)

All HTTP responses now include industry-standard security headers:

Header Value Protection
Content-Security-Policy default-src 'self', connect-src includes Stellar origins Prevents XSS, data injection
Strict-Transport-Security max-age=63072000; includeSubDomains; preload Forces HTTPS (1 year)
X-Content-Type-Options nosniff Prevents MIME sniffing
X-Frame-Options DENY Prevents clickjacking
Referrer-Policy strict-origin-when-cross-origin Controls referrer leakage
Permissions-Policy camera=(), microphone=(), geolocation=() Restricts browser API access
Cache-Control no-store, max-age=0 (HTML documents only) Prevents sensitive page caching

The middleware config excludes _next/static, _next/image, favicon.ico, PWA icons, and sw.js from processing — preserving Next.js static asset caching.

🛡️ CSRF Protection (src/lib/security/csrf.ts)

  • Cryptographically secure token generation using crypto.randomBytes() (32 bytes)
  • HMAC-SHA256 signing with constant-time comparison via timingSafeEqual to prevent timing attacks
  • CSRF token provisioning at GET /api/csrf-token — returns a signed __Host-csrf-token cookie
  • All state-changing methods (POST, PUT, PATCH, DELETE) on /api/* routes require valid x-csrf-token header
  • Cookies use HttpOnly, SameSite=Strict, Secure (production), and __Host- prefix

✅ Input Validation (src/lib/validation/schemas.ts)

Zod v4 schemas for all critical input types:

Schema Validation
stellarAddressSchema G[A-Z2-7]{55} — Stellar public key with base32 checksum
stellarSecretSchema S[A-Z2-7]{55} — Stellar secret key
stellarContractIdSchema C[A-Z2-7]{55} — Stellar contract ID
amountSchema Positive numeric string → parsed value
rateSchema Non-negative numeric string
meterIdSchema Alphanumeric + hyphens/underscores, max 64 chars
meterRegistrationSchema Full meter registration (meterId + reading + rate + owner)
meterReadingSchema Meter reading submission with optional signature
billingPeriodSchema Start/end date validation with ordering check
billingRecordSchema Full billing record validation
transactionEnvelopeSchema Base64 XDR envelope validation
transactionSimulationSchema Transaction simulation request
walletOriginSchema Wallet origin validation against trusted origins
safeStringSchema Generic XSS-safe string (blocks <script>, event handlers)
emailSchema RFC 5322 email validation
urlSchema URL format validation
exportConfigSchema Export configuration with format, columns, date range

🧹 Input Sanitization (src/lib/validation/sanitize.ts)

Multi-layer sanitization to prevent XSS and injection attacks:

  • escapeHtml() — HTML entity escaping (<, >, ", ', &, /, `, =)
  • sanitizeString() — Removes <script>, <style>, HTML comments, event handlers (on*=), javascript:, data:text/html, vbscript: protocols
  • sanitizeObject() — Recursive object sanitization for entire request bodies
  • sanitizeUrl() — Blocks dangerous URL protocols, allows only http:, https:, and relative URLs
  • sanitizeFileName() — Path traversal prevention (removes /, \, .., control chars, limits to 255 chars)
  • sanitizeSqlInput() — Strips SQL-significant characters and keywords (defense in depth)

🔐 Environment Variable Validation (src/lib/security/env.ts)

  • validatePublicEnv() — Validates all NEXT_PUBLIC_* variables at build time (called from next.config.ts)
  • validateServerEnv() — Validates server-side variables at startup; throws in production if critical vars are missing
  • detectSecretLeaks() — Scans all NEXT_PUBLIC_* vars for secret patterns (keys, passwords, tokens, mnemonics, Stellar secret keys); throws in production if leaks detected
  • Zod v4 schemas with sensible defaults for development
  • Validates: NEXT_PUBLIC_BASE_URL, NEXT_PUBLIC_STELLAR_NETWORK, RPC URLs, Horizon URLs, BACKEND_URL, CSRF_SECRET, NODE_ENV, DATABASE_URL, STELLAR_SECRET_KEY, rate limits

🔄 Transaction Simulation (src/lib/security/transaction-simulation.ts)

Before a user signs a transaction, the app now previews:

  • Live RPC simulation — Calls Soroban RPC simulateTransaction endpoint when configured
  • Client-side fallback — Estimates costs and parses operation types from XDR when no RPC available
  • Human-readable summaries — Detects payment, createAccount, manageOffer, changeTrust, setOptions, and invokeHostFunction operations
  • Resource fee estimation — CPU instructions, RAM, ledger reads/writes, total XLM cost
  • State change preview — Contract state modifications with old/new values
  • Event preview — Contract events with topics and data

📋 CI Pipeline (ci.yml)

  • New security-audit job: npm audit --audit-level=high on every push/PR
  • New lint-and-typecheck job: npm run lint + npm run typecheck before build
  • Build job: Sequenced after both security + lint/typecheck jobs pass

📄 Documentation

  • SECURITY.md: Comprehensive security policy covering supported versions, security model, all security features with configuration tables, vulnerability disclosure policy, security assumptions (trusted/untrusted boundaries), development guidelines, and a pre-deployment checklist

🧹 ESLint Configuration

  • Added public/sw.js to ignore list (minified service worker bundle)

🐛 Fixed Pre-existing Issues

  • Fixed 4 lint errors in src/lib/hooks/usePwaInstall.ts, src/lib/hooks/useOnlineStatus.ts, src/components/common/OfflineBanner.tsx, and app/offline/page.tsx (synchronous setState in effects)

Files Changed

File Change
src/middleware.ts New — Security headers + CSRF + wallet origin validation
src/lib/security/csrf.ts New — CSRF token generation & verification
src/lib/security/env.ts New — Environment variable validation
src/lib/security/transaction-simulation.ts New — Soroban transaction simulation
src/lib/validation/schemas.ts New — Zod schemas (229 lines)
src/lib/validation/sanitize.ts New — XSS/injection sanitization (165 lines)
SECURITY.md New — Security documentation (152 lines)
next.config.ts Modified — Security headers + build-time env validation
.github/workflows/ci.yml Modified — Added security-audit + typecheck jobs
eslint.config.mjs Modified — Exclude public/sw.js
package.json Modified — Added zod dependency

Verification

  • npm run lint0 errors, 0 warnings
  • npm run typecheck — All types compile
  • npm run build — Production build succeeds
  • ✅ CSRF token endpoint returns signed cookies
  • ✅ Security headers present on all routes
  • ✅ Environment validation runs at build time
  • ✅ Transaction simulation parses payment, contract invocation, and account operations

Testing Instructions

  1. Security headers: curl -I http://localhost:3000 — verify CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy are present
  2. CSRF token: curl http://localhost:3000/api/csrf-token — returns JSON with token and sets cookie
  3. CSRF protection: curl -X POST http://localhost:3000/api/export without token → 403
  4. CSP: Try injecting <script>alert('xss')</script> → blocked by CSP
  5. Input validation: Submit invalid Stellar address → Zod validation error
  6. Transaction simulation: Import simulateTransaction with a valid XDR → preview costs and state changes

@KarenZita01
KarenZita01 merged commit 41a31bb into EquipChain:main Jul 29, 2026
6 checks passed
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.

[Security] Harden Application with CSP, Security Headers, Input Validation, and CSRF Protection

2 participants