Security Audit Report
Date: February 7, 2026
Scope: Backend codebase (src/backend/)
Executive Summary
This report identifies security vulnerabilities across the backend codebase, categorized by severity. The codebase demonstrates good security practices in many areas (parameterized queries, PKCE, encryption, RBAC) with specific gaps that need addressing.
Overall Security Posture: Moderate — good foundation with critical gaps.
Critical Issues
1. In-Memory Rate Limiting (No Persistence)
File: middleware/ratelimit.ts
Rate limiting uses an in-memory Map that resets on worker cold starts and doesn't share state across instances. Attackers can bypass limits by waiting for cold starts or hitting different isolates.
Recommendation: Use Durable Objects, KV, or Cloudflare's built-in rate limiting.
2. CORS Allows All Origins When ALLOWED_ORIGINS Not Set
File: op.ts
OAuth2 endpoints allow any origin when ALLOWED_ORIGINS is not set, enabling CSRF attacks.
Recommendation: Require ALLOWED_ORIGINS in production. Never default to *.
3. Missing CSRF Protection on Stateful Operations
File: rp.ts
OAuth state is validated, but no CSRF token protection for general POST/PUT/DELETE API operations.
Recommendation: Implement CSRF token validation for all state-changing operations.
High Issues
4-6. SQL Injection Risk in Dynamic Query Construction
Files: idp.ts, roles.ts, users.ts
Dynamic SQL query construction uses string concatenation for column names. While parameters are bound, the pattern is fragile.
`UPDATE identity_providers SET ${updates.join(", ")} WHERE id = ?`Recommendation: Validate all field names against a strict whitelist before building queries.
7. Error Messages Leak Information
Files: Multiple
Error messages in catch blocks include details that could leak system information.
Recommendation: Return generic error messages to clients; log details server-side only.
8. Missing Input Validation on URL Parameters
File: op.ts
OAuth authorization endpoint parameters lack comprehensive validation.
Recommendation: Validate all query parameters against strict patterns.
9. Authorization Code Replay Prevention Gap
File: op.ts
Authorization codes are deleted after retrieval, but if deletion fails, codes could be reused.
Recommendation: Use atomic operations (DELETE with RETURNING) for one-time consumption.
10. Session Token Not Invalidated on User Disable
File: middleware/auth.ts
Existing session tokens remain valid when a user is disabled until they naturally expire.
Recommendation: Implement token revocation on user disable.
Medium Issues
| # | Issue | File | Recommendation |
|---|---|---|---|
| 11 | Weak rate limiting configuration | ratelimit.ts | Stricter limits for auth endpoints |
| 12 | Missing rate limiting on some endpoints | Multiple | Apply to all endpoints |
| 13 | CORS credentials inconsistency | index.ts vs op.ts | Standardize configuration |
| 14 | Hardcoded default issuer/audience | token.ts | Require in production, fail fast |
| 15 | JWKS signing endpoint unauthenticated | jwks.ts | Add auth checks or ensure internal-only |
| 16 | Refresh token rotation not atomic | op.ts | Use database transactions |
| 17 | Missing validation on JWT payload | token.ts | Validate before signing |
| 18 | Session expiration not consistent | sessions.ts | Enforce expiration on all operations |
| 19 | Missing input sanitization | users.ts, roles.ts | Sanitize user input before storage |
| 20 | Audit logging failures are silent | audit.ts | Alert on failures |
Low Issues
| # | Issue | Recommendation |
|---|---|---|
| 21 | TODO comment about master key | Remove or clarify |
| 22 | console.error for security events | Use structured logging |
| 23 | Missing CSP headers | Add Content-Security-Policy |
| 24 | Missing HSTS on all routes | Ensure HSTS is global |
| 25 | No master key strength validation | Validate at startup |
| 26 | Missing request ID in some errors | Include in all responses |
| 27 | Clock skew tolerance may be too high | Consider reducing to 5-10s |
| 28 | No redirect URI length validation | Add max length check |
Positive Practices
- All database queries use parameterized statements
- PKCE with S256 required for all OAuth flows
- Sensitive tokens and secrets encrypted at rest
- Proper session tracking and revocation
- Role-based access control implemented
- SSRF protection for IdP URLs
- Zod schemas for request validation
- Comprehensive audit logging
- Refresh token rotation on refresh
- Email verification required for bootstrap admin
Remediation Priority
Immediate (Critical/High)
- Replace in-memory rate limiting with Durable Objects/KV
- Fix CORS to require ALLOWED_ORIGINS in production
- Add CSRF protection for state-changing operations
- Harden dynamic SQL query construction
- Sanitize error messages returned to clients
- Implement atomic authorization code consumption
Short-term (Medium)
- Tighten rate limiting configuration
- Standardize CORS configuration
- Require ISSUER/AUDIENCE environment variables
- Implement atomic refresh token rotation
Long-term (Low)
- Add CSP headers
- Improve logging infrastructure
- Validate master key strength at startup