This document describes the security measures implemented in Talk-To-My-Lawyer application.
Location: lib/rate-limit.ts
The application now includes an in-memory rate limiter to prevent brute force attacks.
Features:
- Configurable request limits and time windows
- Automatic cleanup of expired entries
- Client identification via IP address (supports proxy headers)
Usage Example:
import { rateLimit, getClientIdentifier } from "@/lib/rate-limit";
const identifier = getClientIdentifier(request);
const result = rateLimit(`endpoint-name:${identifier}`, {
maxRequests: 5,
windowMs: 15 * 60 * 1000, // 15 minutes
});
if (!result.success) {
return NextResponse.json(
{ error: "Too many requests" },
{ status: 429 }
);
}Current Implementation:
- Admin secret verification: 5 attempts per 15 minutes per IP
Production Considerations: For production deployment at scale, consider replacing the in-memory store with:
- Redis
- Upstash Rate Limit
- Cloudflare Rate Limiting
Location: lib/rate-limit.ts
All secret comparisons now use constant-time comparison to prevent timing attacks.
Function: constantTimeEqual(a: string, b: string)
This prevents attackers from determining the correct secret by measuring response times.
All API endpoints now validate input data:
Admin Secret Verification (app/api/admin/verify-secret/route.ts):
- Max length: 100 characters
- Type validation: string only
- Rate limited: 5 attempts per 15 minutes
Coupon Validation (app/api/validate-coupon/route.ts):
- Max length: 50 characters
- Format validation: alphanumeric, hyphens, and underscores only
- Pattern:
^[A-Za-z0-9_-]+$
Location: lib/env-validation.ts
The application validates all required environment variables at startup.
Required Variables:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYADMIN_SIGNUP_SECRET
Optional Variables (feature-dependent):
STRIPE_SECRET_KEYNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYANTHROPIC_API_KEY
Functions:
validateEnv(throwOnError): Validates all environment variablesgetRequiredEnv(name): Gets a required env var or throws errorgetOptionalEnv(name, default): Gets an optional env var with default
Usage:
import { getRequiredEnv } from "@/lib/env-validation";
const apiKey = getRequiredEnv("SOME_API_KEY");All Supabase clients now use getRequiredEnv() instead of non-null assertions (!).
When creating a new API route, ensure you:
- Add input validation for all parameters
- Implement rate limiting for sensitive endpoints
- Use constant-time comparison for secrets
- Validate environment variables
- Return appropriate HTTP status codes
- Avoid exposing internal error details
- Log security-relevant events
The middleware enforces authentication and role-based access control:
Protected Paths:
/dashboard/*- Requires authentication/admin/*- Requires admin role
Role Hierarchy:
admin: Full access to all routesemployee: Access to employee dashboardsubscriber: Access to subscriber dashboard
-
In-Memory Rate Limiting: Current implementation uses in-memory storage which:
- Resets on server restart
- Doesn't work across multiple instances
- Not suitable for horizontal scaling
-
Missing Audit Logging: Admin actions are not currently logged
-
No CAPTCHA: Rate limiting alone may not prevent sophisticated attacks
- Replace In-Memory Rate Limiting: Use Redis or Upstash
- Implement Audit Logging: Track all admin actions and sensitive operations
- Add CAPTCHA: Protect authentication and admin endpoints
- Enable CORS: Configure appropriate CORS policies
- Add Request ID: Include request IDs for debugging and security analysis
- Implement CSP Headers: Add Content Security Policy headers
- Enable HSTS: Use HTTP Strict Transport Security
- Add Security Headers: X-Frame-Options, X-Content-Type-Options, etc.
- Set up Error Tracking: Use Sentry or similar service
- Implement IP Allowlisting: For admin endpoints if applicable
- Add Request Signing: For API requests from trusted clients
- Implement API Keys: For programmatic access
- Add Webhooks: For security events
- Enable 2FA: For admin accounts
# Test admin secret endpoint
for i in {1..6}; do
curl -X POST http://localhost:3000/api/admin/verify-secret \
-H "Content-Type: application/json" \
-d '{"secretKey":"wrong-secret"}'
echo "Attempt $i"
doneAfter 5 attempts, you should receive a 429 status code.
# Test coupon validation with invalid characters
curl "http://localhost:3000/api/validate-coupon?code=INVALID<>CHARS"
# Test with too long string
curl "http://localhost:3000/api/validate-coupon?code=$(python3 -c 'print("A"*51)')"# Start the app without required env vars
unset NEXT_PUBLIC_SUPABASE_URL
npm run devThe app should fail to start with a clear error message.
If you detect suspicious activity:
- Check server logs for the attacker's IP address
- Review rate limit violations
- Check database for unauthorized access
- Rotate secrets if compromised
- Block malicious IPs at firewall/proxy level
- Review and update security measures
For security issues, please report to:
- Create a private security advisory on GitHub
- Or contact the development team directly
- Added rate limiting middleware
- Implemented constant-time string comparison
- Added input validation to all API endpoints
- Implemented environment variable validation
- Updated Supabase clients to use safe env variable access
- Created security documentation