Security Overview - jra3/mulm GitHub Wiki
Last Updated: November 4, 2025
The BASNY BAP platform has undergone comprehensive security hardening and now maintains an A security grade with defense-in-depth authentication protection.
Major Security Milestone: All high-priority authentication vulnerabilities fixed on October 7, 2025.
SQL Injection Prevention (A+)
- 100% parameterized queries throughout codebase
- Proper prepared statement usage with finalization
- Transaction support with rollback handling
- Zero SQL injection vectors identified
Infrastructure Security (A)
- HTTPS enforced with HSTS (max-age=31536000, preload)
- TLS 1.2+ only, strong cipher suites
- Security headers (X-Frame-Options, X-Content-Type-Options, CSP)
- nginx rate limiting (10r/s general, 30r/s API, 5r/s uploads)
- Server tokens disabled (nginx + Express)
- Default server block rejects invalid Host headers
File Upload Security (A)
- Multi-layer validation (MIME type, magic bytes, Sharp metadata)
- Dimension constraints (400px-4000px)
- EXIF stripping for privacy
- Comprehensive rate limiting (per-user + IP-based)
- 10MB file size limit
- Authentication required for uploads
- Transaction-based cleanup on failure (#68, #69)
Authentication Security (A) - NEW! ✨
- OAuth CSRF protection with state parameter (#81)
- Session fixation prevention (ID regeneration on auth) (#82)
- Timing attack mitigation (constant-time operations) (#78)
- Rate limiting on all auth endpoints (#77)
- Account lockout (5 attempts/15min, auto-recovery) (#79)
- Password complexity requirements (configurable levels) (#85)
- Comprehensive logging of suspicious activity
Input Validation (A-)
- Zod schemas for all forms
- Server-side validation with field-level errors
- Type safety via TypeScript
- Pug templates auto-escape output
- Maximum field lengths enforced (#87)
Password Security (A) - UPGRADED! ✨
- scrypt KDF (N=16384, r=8, p=1)
- Random 16-byte salts
- Server-side storage only
- Minimum 12 character requirement (#85)
- Configurable complexity levels (1-3)
- NIST-compliant (prioritizes length over complexity)
Session Management (A) - UPGRADED! ✨
- httpOnly, secure, sameSite: 'lax' cookies
- Server-side session storage (SQLite)
- 180-day expiry with database validation
- Session regeneration on authentication (#82)
- OAuth state tracking for CSRF protection
- Proper cleanup on logout
Accessibility (A) - NEW! ✨
- WCAG 2.1 Level AA compliant
- Semantic HTML with proper ARIA labels
- Screen reader support throughout
- Date fields use
<time>elements with datetime attributes - Form validation with accessible error messages
- Loading states prevent accidental resubmission (#49, #34)
All previously identified vulnerabilities have been fixed:
1. ✅ Authentication Timing Attacks (Fixed Oct 7, 2025)
- Issue: Email enumeration via response time differences
- Fix: Constant-time password check with dummy hash
- Fix: Forgot password simulates operations (300ms delay)
- Commit: f0be693
- Status: RESOLVED
2. ✅ No Account Lockout (Fixed Oct 7, 2025)
- Issue: Unlimited login attempts allowed
- Fix: 5 attempts within 15min → 15min lockout
- Fix: Auto-recovery, cleared on successful login
- Commit: fa3d8d6
- Status: RESOLVED
3. ✅ OAuth Missing State Parameter (Fixed Oct 7, 2025)
- Issue: OAuth CSRF vulnerability
- Fix: State parameter validation, one-time use
- Commit: 1dbab33, 5f48a95
- Status: RESOLVED
4. ✅ Session Fixation (Fixed Oct 7, 2025)
- Issue: Session ID not regenerated on authentication
- Fix: Session ID regeneration on all auth events
- Commit: 077af06
- Status: RESOLVED
5. ✅ No Authentication Rate Limiting (Fixed Oct 7, 2025)
- Issue: Brute force attacks possible
- Fix: Login: 5/15min, Signup: 3/hour, Forgot: 3/hour, OAuth: 10/5min
- Commit: 69c539d, 47010c4
- Status: RESOLVED
6. ✅ Weak Password Policy (Fixed Oct 7, 2025)
- Issue: No minimum password requirements
- Fix: 12 character minimum, 3 configurable complexity levels
- Commit: eae9754
- Status: RESOLVED
7. ✅ Secrets in config.json (Decision Oct 7, 2025)
- Issue: All secrets in one unencrypted file
- Decision: Keep in config.json with 600 permissions
- Rationale: File properly secured, deployment model appropriate
- Status: ACCEPTED AS-IS
Our security approach uses layered defenses so that if one layer fails, others protect the system:
Layer 1: Network & Infrastructure
- HTTPS/TLS encryption
- nginx rate limiting (general)
- HSTS header
Layer 2: Application Rate Limiting
- 5 login attempts per 15 minutes (per IP+email)
- 3 signup attempts per hour (per IP)
- 3 password reset attempts per hour (per IP)
- 10 OAuth attempts per 5 minutes (per IP)
Layer 3: Account Lockout
- 5 failed attempts within 15 minutes → 15 minute lockout
- Auto-recovery (no admin intervention)
- Failed attempts tracked per account
- Cleared on successful login
Layer 4: Authentication Security
- Session fixation prevention (regenerate ID on auth)
- OAuth CSRF protection (state parameter validation)
- Timing attack mitigation (constant-time operations)
- Strong password requirements (12+ characters)
Layer 5: Session Security
- httpOnly cookies (XSS protection)
- Secure flag (HTTPS only)
- sameSite: 'lax' (CSRF protection)
- Server-side storage
- Session regeneration
Layer 6: Password Storage
- scrypt KDF with strong parameters
- 16-byte random salts
- Server-side only
- No client-side password storage
| Threat | Likelihood | Impact | Mitigation | Status |
|---|---|---|---|---|
| Brute Force Password Attack | Medium | High | Rate limiting + Account lockout + Strong passwords | ✅ MITIGATED |
| Credential Stuffing | Medium | High | Rate limiting + Account lockout + Timing protection | ✅ MITIGATED |
| Email Enumeration | Low | Low | Timing attack fixes + Generic error messages | ✅ MITIGATED |
| Session Hijacking | Low | High | httpOnly + secure + sameSite cookies + HTTPS | ✅ MITIGATED |
| Session Fixation | Low | Medium | Session ID regeneration on authentication | ✅ MITIGATED |
| OAuth CSRF | Low | Medium | State parameter validation (one-time use) | ✅ MITIGATED |
| Password Spraying | Medium | Medium | Rate limiting + Account lockout | ✅ MITIGATED |
| Timing Attacks | Low | Low | Constant-time password check + Simulated operations | ✅ MITIGATED |
| Threat | Likelihood | Impact | Mitigation | Status |
|---|---|---|---|---|
| SQL Injection | Low | Critical | 100% parameterized queries | ✅ MITIGATED |
| XSS | Low | High | Pug auto-escaping + CSP headers | ✅ MITIGATED |
| File Upload Abuse | Medium | Medium | Multi-layer validation + Rate limiting + Size limits | ✅ MITIGATED |
| Data Loss | Low | Critical | EBS snapshots + Termination protection + 5 safety layers | ✅ MITIGATED |
| DDoS | Medium | High | nginx rate limiting + Application rate limiting | ✅ MITIGATED |
| Threat | Likelihood | Impact | Mitigation | Status |
|---|---|---|---|---|
| Privilege Escalation | Low | High | Admin middleware + Database-level checks | ✅ MITIGATED |
| Unauthorized Data Access | Low | High | Session-based auth + Viewer checks | ✅ MITIGATED |
| CSRF (General) | Medium | Medium | sameSite cookies + Future token implementation | 🔄 PARTIAL |
All security-relevant events are logged:
- Failed login attempts (with IP and email)
- Account lockouts
- OAuth state validation failures
- Rate limit violations
- Session regeneration events
- Suspicious activity patterns
Log Location: Application logs via winston logger
- Failed login rate
- Account lockout frequency
- Rate limit trigger frequency
- OAuth validation failures
- Session creation patterns
Frameworks Followed:
- ✅ OWASP Top 10 (2021)
- ✅ NIST Digital Identity Guidelines (SP 800-63B)
- ✅ WCAG 2.1 Level AA (Accessibility)
Security Headers:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadX-Frame-Options: SAMEORIGINX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-origin
Completed Today:
- ✅ OAuth CSRF Protection (#81) - State parameter with one-time validation
- ✅ Session Fixation Prevention (#82) - Session ID regeneration on auth
- ✅ Timing Attack Mitigation (#78) - Constant-time operations
- ✅ Authentication Rate Limiting (#77) - Multi-tier rate limits
- ✅ Account Lockout (#79) - 5 attempts/15min with auto-recovery
- ✅ Password Complexity (#85) - 12 char minimum, 3 configurable levels
- ✅ Image Upload Cleanup (#68, #69) - Transaction-based cleanup
Impact: Authentication system upgraded from B- to A grade
- General CSRF Protection (#19) - Token-based protection for all state-changing operations
- Estimated: 4-6 hours
- File Virus Scanning (#65) - ClamAV integration for uploaded images
- Concurrent Session Limiting (#86) - Limit active sessions per user
- Enhanced Logging - Structured logging with correlation IDs
- Security Headers Enhancement - Content-Security-Policy refinement
- ✅ 44 security-related tests
- ✅ Rate limiter tests (10 tests)
- ✅ Account lockout tests (10 tests)
- ✅ Password complexity tests (12 tests)
- ✅ OAuth state validation tests (pending)
- ✅ Authentication flows (signup, login, OAuth, password reset)
- ✅ Rate limiting verification
- ✅ Account lockout verification
- ✅ Loading indicators and double-click prevention
If you discover a security vulnerability:
- Create a GitHub issue with
securitylabel - Mark as private if sensitive
- Include reproduction steps
- Response SLA: 24 hours for critical, 72 hours for medium/low
- Implemented OAuth state parameter CSRF protection
- Implemented session fixation prevention
- Fixed timing attacks in authentication flows
- Added comprehensive rate limiting to all auth endpoints
- Implemented account lockout mechanism (5 attempts/15min)
- Added password complexity requirements (12 char minimum)
- Enhanced form accessibility (ARIA labels, validation)
- Added HTMX loading indicators (double-click prevention)
- Security Grade: B+ → A
- Fixed logout CSRF vulnerability
- Enabled Dependabot
- Fixed 4 npm package vulnerabilities
- Comprehensive security audit completed
- Security Grade: B → B+