7.5 KiB
7.5 KiB
LexMind Security Audit Report
Date: 2026-02-01 Auditor: Automated Security Audit Status: ✅ COMPLETED
Executive Summary
Comprehensive security audit of the LexMind application (Next.js 16 + Prisma + PostgreSQL + NextAuth + Stripe). Found and fixed 12 vulnerabilities across 7 categories. Zero npm vulnerabilities remain.
1. NPM Vulnerabilities
Status: ✅ FIXED
| Before | After |
|---|---|
| 21 high severity | 0 vulnerabilities |
- Root cause:
fast-xml-parser5.2.5 (via AWS SDK) had RangeError DoS bug - Fix: Added npm override for
fast-xml-parser@5.3.4in package.json
2. SQL Injection / Prisma
Status: ✅ CLEAN
- No
$queryRawor$executeRawusage found - All database access uses Prisma's parameterized queries
- No raw SQL anywhere in the codebase
3. XSS (Cross-Site Scripting)
Status: ✅ CLEAN
- No
dangerouslySetInnerHTMLorinnerHTMLusage found - React's default escaping protects against XSS
- Added Content-Security-Policy header (see Section 9)
4. CSRF Protection
Status: ✅ VERIFIED
- NextAuth CSRF tokens working correctly
- Cookies use
__Host-prefix withHttpOnly; Secure; SameSite=Lax - All mutating API routes require authenticated session
5. Authentication & Authorization
Status: ✅ FIXED (2 critical issues)
🔴 CRITICAL: Unauthenticated Checkout Route
- File:
/api/checkout/route.ts - Issue: No
getServerSessioncheck — anyone could create Stripe checkout sessions - Fix: Added authentication check, uses session email instead of user-provided email
🔴 CRITICAL: Unauthenticated DOCX Export Route
- File:
/api/export/docx/route.ts - Issue: No authentication — anyone could generate DOCX documents
- Fix: Added
getServerSessioncheck
Auth Coverage (all routes verified):
| Route | Auth | IDOR Protected |
|---|---|---|
| /api/admin/stats | ✅ ADMIN check | N/A |
| /api/analise-processo | ✅ session.user.id | ✅ userId filter |
| /api/analise-processo/[id] | ✅ session.user.id | ✅ userId filter |
| /api/auditoria | ✅ session.user.id | ✅ userId filter |
| /api/auditoria/[id] | ✅ session.user.id | ✅ userId filter |
| /api/chat | ✅ session.user.id | ✅ userId filter |
| /api/chat/[chatId] | ✅ session.user.id | ✅ userId filter |
| /api/checkout | ✅ FIXED | N/A |
| /api/documents | ✅ session.user.id | ✅ userId filter |
| /api/documents/[id] | ✅ session.user.id | ✅ userId filter |
| /api/documents/generate | ✅ session.user.id | N/A |
| /api/export/docx | ✅ FIXED | N/A |
| /api/jurisprudencia | ✅ session.user.id | N/A (public data) |
| /api/jurisprudencia/search | ✅ session.user.id | N/A (public data) |
| /api/keys | ✅ session.user.id | ✅ userId filter |
| /api/keys/[id] | ✅ session.user.id | ✅ userId filter |
| /api/prazos | ✅ session.user.id | ✅ userId filter |
| /api/prazos/[id] | ✅ session.user.id | ✅ userId filter |
| /api/register | N/A (public) | N/A |
| /api/stripe/checkout | ✅ session.user | ✅ |
| /api/stripe/portal | ✅ session.user | ✅ |
| /api/stripe/webhook | N/A (Stripe sig) | ✅ signature verified |
| /api/templates | ✅ session.user.id | ✅ userId filter |
| /api/uploads | ✅ session.user.id | ✅ userId filter |
| /api/uploads/[id] | ✅ session.user.id | ✅ userId filter |
6. Rate Limiting
Status: ✅ VERIFIED
Nginx rate limiting active:
- Auth routes: 5 req/min (
zone=auth) - API routes: 20 req/sec (
zone=api) - General: 30 req/sec (
zone=general) - Connection limit: 20 per IP (
conn_limit) - Scanner/bot blocking via User-Agent filter
7. Input Validation
Status: ✅ FIXED (5 improvements)
- Created:
src/lib/validate.tswith sanitization utilities - Register route: Added input length limits for all fields
- Chat route: Added 10,000 char message limit
- Auditoria route: Added title (500) and content (100,000) limits
- Prazos route: Added title (500) and description (5,000) limits
- Pagination: Bounded page/limit params in uploads and jurisprudencia routes
- Uploads: Added server-side file extension validation (defense in depth)
8. Sensitive Data Exposure
Status: ✅ FIXED
- Created
.gitignore—.envwas not being excluded (no.gitignoreexisted!) - Stripe error messages: Stopped leaking
error.messageto client in checkout/portal routes - API responses: Verified no password hashes or internal IDs are exposed
- API keys: Properly hashed (SHA-256), only shown once on creation, masked in listings
- NEXT_PUBLIC vars: Only publishable Stripe key and app URL (safe)
- Error handling: All routes return generic error messages, details logged server-side
9. Security Headers
Status: ✅ FIXED (2 new headers added)
Headers now active:
| Header | Value | Status |
|---|---|---|
| X-Frame-Options | SAMEORIGIN | ✅ existing |
| X-Content-Type-Options | nosniff | ✅ existing |
| X-XSS-Protection | 1; mode=block | ✅ existing |
| Referrer-Policy | strict-origin-when-cross-origin | ✅ existing |
| Strict-Transport-Security | max-age=31536000; includeSubDomains | ✅ existing |
| Content-Security-Policy | Full CSP policy | ✅ ADDED |
| Permissions-Policy | camera=(), microphone=(), geolocation=() | ✅ ADDED |
| server_tokens | off | ✅ existing |
10. Database Security
Status: ✅ VERIFIED
- PostgreSQL listens only on localhost (default,
listen_addresses = 'localhost') pg_hba.confusesscram-sha-256for TCP connections- Local connections use
peerauthentication - No remote access configured
11. File Upload Security
Status: ✅ VERIFIED + IMPROVED
- MIME type whitelist: PDF, DOC, DOCX, TXT only
- Added: File extension validation (defense in depth)
- Max size: 50MB (enforced both in app and nginx
client_max_body_size) - Storage limits per plan (1GB-20GB)
- File paths sanitized via
buildKey()— strips all special chars - No path traversal possible (
../becomes___) - Files stored as
privateACL on DigitalOcean Spaces - Access via signed URLs (15 min expiry)
12. Session Security
Status: ✅ IMPROVED
- Cookies:
__Host-prefix,HttpOnly,Secure,SameSite=Lax - Reduced session maxAge from 30 days to 7 days (more appropriate for legal app)
- JWT strategy with strong NEXTAUTH_SECRET (44 chars, base64)
- CSRF token verified on all auth requests
13. Other Fixes
Duplicate Webhook Route Removed
- Deleted:
/api/webhook/stripe/route.ts(incomplete, only logged events, no DB updates) - Active:
/api/stripe/webhook/route.ts(fully functional with DB updates)
Next.js Middleware Added
- Created:
src/middleware.ts— adds security headers at application level as backup
14. Remaining Notes (Low Risk)
| Item | Risk | Notes |
|---|---|---|
typescript: { ignoreBuildErrors: true } in next.config |
Low | Could hide type errors; recommend fixing eventually |
| AWS SDK DoS vuln was in XML parsing | Info | Fixed via override, but only exploitable if attacker controls S3 responses |
| File upload MIME check trusts client header | Low | Mitigated by extension whitelist + private storage |
| No email verification on registration | Medium | Users can register with unverified emails |
Deployment Status
- ✅ All fixes applied
- ✅
npm audit: 0 vulnerabilities - ✅ Build successful
- ✅ PM2 restarted
- ✅ Nginx reloaded with new headers
- ✅ Application verified working