Skip to content

fix(security): address security vulnerabilities across frontend and backend#87

Merged
stevenferey merged 11 commits intodevelopfrom
fix/security-vulnerabilities
Mar 9, 2026
Merged

fix(security): address security vulnerabilities across frontend and backend#87
stevenferey merged 11 commits intodevelopfrom
fix/security-vulnerabilities

Conversation

@stevenferey
Copy link
Owner

Summary

  • Sanitize HTML in email templates — prevent stored XSS via malicious firstName during registration
  • Remove AI API key from client bundleVITE_AI_API_KEY was exported in the frontend JS, visible to anyone
  • Require authentication for signature upload — add authenticate middleware on backend + credentials/token on frontend
  • Require JWT secrets via environment variables — throw at startup instead of falling back to predictable defaults
  • Enable SSL certificate verification for PostgreSQL — default rejectUnauthorized to true in production
  • Remove PII (emails) from logs — replace email addresses with user IDs in backend and frontend logs
  • Default cookie secure flag to true — only disable in explicit development mode
  • Store access token in memory instead of localStorage — reduce XSS attack surface, rely on httpOnly refresh cookie
  • Add helmet middleware — set standard HTTP security headers on all backend responses

Breaking changes

  • JWT secrets required: The backend will refuse to start without JWT_ACCESS_SECRET and JWT_REFRESH_SECRET environment variables
  • Session persistence: Users will need to re-login after deploy (access token is no longer persisted in localStorage; session recovery uses the httpOnly refresh cookie)
  • SSL verification: Production deployments using self-signed DB certs must set DB_SSL_REJECT_UNAUTHORIZED=false

Test plan

  • Vérifier que le backend démarre avec les variables JWT configurées
  • Vérifier que le backend refuse de démarrer sans les variables JWT
  • Tester login/logout/refresh — la session doit se restaurer via le cookie après rafraîchissement de page
  • Tester l'upload de signature (doit fonctionner connecté, échouer déconnecté)
  • Vérifier les headers de sécurité avec curl -I sur un endpoint
  • Vérifier qu'un firstName contenant du HTML est échappé dans les emails
  • Vérifier que aiApiKey n'apparaît plus dans le bundle JS (npm run build puis grep)

🤖 Generated with Claude Code

stevenferey and others added 11 commits March 9, 2026 21:27
Add escapeHtml() to sanitize firstName before interpolation in
email templates, preventing stored XSS via malicious registration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove VITE_AI_API_KEY from frontend code, env types, and
documentation. VITE_ prefixed variables are bundled into the
client JS and visible to anyone inspecting the source.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the default admin user (admin@crafter.app / admin123) from
the migration file. Admin users should be created via a dedicated
seed script instead of being embedded in migration history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add authenticate middleware to the upload route on the backend.
On the frontend, include credentials and Authorization header
in the upload fetch request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Throw a fatal error at startup if JWT_ACCESS_SECRET or
JWT_REFRESH_SECRET are not set, instead of falling back to
predictable default values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tgreSQL

Default rejectUnauthorized to true in production. Providers using
self-signed certs (e.g. Railway) can opt out explicitly via
DB_SSL_REJECT_UNAUTHORIZED=false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace user email addresses with user IDs in backend auth logs.
Remove email from frontend store logs and email service logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Invert the logic so cookies are secure by default. Only disable
the secure flag when NODE_ENV is explicitly 'development'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Zustand persist middleware with in-memory token store.
Access tokens are no longer written to localStorage, reducing
the XSS attack surface. Session recovery after page refresh
relies on the httpOnly refresh token cookie.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add helmet to set security headers (X-Content-Type-Options,
X-Frame-Options, Strict-Transport-Security, etc.) on all
backend responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restore hardcoded admin credentials in the migration file.
The default admin password should be changed manually after
installation on each environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stevenferey stevenferey merged commit e49e9d7 into develop Mar 9, 2026
2 checks passed
@stevenferey stevenferey deleted the fix/security-vulnerabilities branch March 9, 2026 20:45
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