Skip to content

Security: Fix critical security vulnerabilities - #199

Merged
parkerwinner merged 1 commit into
parkerwinner:mainfrom
Georgechisom:security/critical-fixes
Jul 30, 2026
Merged

Security: Fix critical security vulnerabilities#199
parkerwinner merged 1 commit into
parkerwinner:mainfrom
Georgechisom:security/critical-fixes

Conversation

@Georgechisom

Copy link
Copy Markdown
Contributor

Security: Fix Critical Security Vulnerabilities

Summary

This PR addresses four critical security vulnerabilities in the authentication and search systems. All changes follow security best practices and include proper validation, parameterized queries, and rate limiting.

Changes

1. Remove Hardcoded JWT Secrets

  • Severity: CRITICAL
  • Removed insecure default values for JWT_SECRET and JWT_REFRESH_SECRET
  • Added validation requiring both secrets to be set via environment variables
  • Enforced minimum length of 32 characters for both secrets
  • Updated .env.example with clear security documentation
  • Application now fails fast at startup if secrets are missing or too short

2. Password Reset Flow

  • Severity: HIGH
  • Implemented complete forgot password flow with email verification
  • Added two new endpoints: /auth/forgot-password and /auth/reset-password
  • Generated cryptographically secure 64-character hex tokens using crypto/rand
  • Tokens expire after 1 hour for security
  • Email templates include token and security warnings
  • Responses don't reveal whether email exists (security best practice)
  • Password reset clears any existing account lockout
  • Added database fields: reset_token, reset_token_expires_at

3. Account Lockout After Failed Logins

  • Severity: CRITICAL
  • Implemented brute force protection on login endpoint
  • Account locks for 30 minutes after 5 failed login attempts within 15-minute window
  • Failed attempt counter resets automatically after 15 minutes of inactivity
  • Failed attempts reset on successful login
  • Clear user feedback when account is locked
  • Added database fields: failed_login_attempts, locked_until, last_failed_login_at
  • Enhanced logging for security monitoring

4. Fix SQL Injection in Search

  • Severity: CRITICAL
  • Replaced all raw SQL queries with parameterized GORM queries
  • Removed string interpolation in SQL ORDER BY clauses
  • Added whitelist validation for sort columns
  • PostgreSQL full-text search uses parameterized plainto_tsquery
  • Fallback LIKE queries use proper parameter binding
  • All user inputs are now safely escaped

Database Migrations

Migration 000006: Password reset functionality

  • Adds reset_token (VARCHAR 255, indexed)
  • Adds reset_token_expires_at (TIMESTAMPTZ)

Migration 000007: Account lockout functionality

  • Adds failed_login_attempts (INT, default 0)
  • Adds locked_until (TIMESTAMPTZ, indexed)
  • Adds last_failed_login_at (TIMESTAMPTZ)

Security Improvements

  • JWT secrets must be cryptographically secure and properly configured
  • Brute force attacks are mitigated with account lockout
  • SQL injection attacks are prevented with parameterized queries
  • Password reset tokens are cryptographically random and time-limited
  • Enhanced audit logging for security events

Testing Notes

Manual testing required for:

  • JWT secret validation on application startup
  • Password reset email delivery and token validation
  • Account lockout after multiple failed login attempts
  • Search functionality with various inputs to verify no SQL injection

Configuration Required

Add to production environment:

JWT_SECRET=<secure-random-32+-char-string>
JWT_REFRESH_SECRET=<secure-random-32+-char-string>

Generate secure secrets using:

openssl rand -hex 32

Closes #185
Closes #186
Closes #187
Closes #188

- Remove hardcoded JWT secret defaults and require environment variables (parkerwinner#185)
- Add password reset flow with email token verification (parkerwinner#186)
- Implement account lockout after 5 failed login attempts in 15 minutes (parkerwinner#187)
- Fix SQL injection vulnerabilities in search using parameterized queries (parkerwinner#188)

Security improvements:
- JWT secrets must be at least 32 characters and set via env vars
- Account locks for 30 minutes after 5 failed logins within 15 minutes
- Password reset tokens expire in 1 hour
- All database queries use parameterized/prepared statements
- Failed login attempts are tracked per user
- Account lockout is automatically cleared on successful password reset

Database migrations:
- Added reset_token and reset_token_expires_at to users table
- Added failed_login_attempts, locked_until, and last_failed_login_at to users table
@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@Georgechisom Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@parkerwinner

Copy link
Copy Markdown
Owner

Good job @Georgechisom

@parkerwinner
parkerwinner merged commit 133b8bd into parkerwinner:main Jul 30, 2026
0 of 3 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

2 participants