Threat Model
This document describes the threats Aero2 protects against and the mitigations in place, based on findings from the security audit.
Threat Categories
1. Token Forgery and Confusion
Threat: Attacker crafts or modifies JWTs to impersonate users or escalate privileges.
Mitigations:- RS256-only algorithm restriction prevents algorithm confusion attacks
- Token type enforcement (
token_useclaim) prevents using access tokens as session tokens - Required claims validation (
sub,iat,exp) - 30-second clock tolerance for distributed system skew
2. Cross-Site Request Forgery (CSRF)
Threat: Attacker tricks authenticated user into making unintended state-changing requests.
Mitigations:SameSite=Stricton session cookies- Origin/Referer header validation on all state-changing requests with cookie authentication
- OAuth state parameter bound to HttpOnly cookie
- Atomic state consumption prevents replay
3. Authorization Code Interception
Threat: Attacker intercepts the OAuth authorization code during the redirect.
Mitigations:- PKCE with S256 method required on all flows (plain method rejected)
- Authorization codes are single-use (atomic DELETE with RETURNING)
- Short expiration (10 minutes)
4. Credential Theft via Database Compromise
Threat: Attacker gains access to the database and extracts credentials.
Mitigations:- Refresh tokens stored as HMAC-SHA256 hashes (not plaintext)
- Client secrets hashed with PBKDF2 (100k iterations, random salt)
- IdP client secrets encrypted with AES-256-GCM
- JWKS private keys managed in Durable Object storage (separate from D1)
5. Open Redirect
Threat: Attacker crafts a login URL that redirects to a malicious site after authentication.
Mitigations:validateRedirectUri()utility validates all redirect targets- Only same-origin paths accepted (must start with
/) - Protocol-relative URLs, external URLs, and
data:URIs rejected - Applied on Login page, OAuth callback, and authorization endpoint
6. Server-Side Request Forgery (SSRF)
Threat: Attacker configures an IdP with internal/private endpoints to probe the network.
Mitigations:- All IdP URLs must be HTTPS
- Private IP ranges blocked (10.x, 172.16-31.x, 192.168.x, 127.x, ::1)
- Localhost blocked (configurable override for development)
7. Session Hijacking
Threat: Attacker obtains a valid session token and impersonates the user.
Mitigations:- Session cookies are HttpOnly (no JavaScript access), Secure (HTTPS only), SameSite=Strict
- HSTS header prevents downgrade attacks
- Sessions tracked with user agent and IP for anomaly detection
- Admin can revoke individual or all sessions
8. Privilege Escalation
Threat: Non-admin user accesses admin-only functionality.
Mitigations:- RBAC middleware checks permissions on every admin endpoint
- Permission checks use
resource:actiongranularity - Bootstrap admin requires verified email match
- Role assignment restricted to admin users
9. Clickjacking
Threat: Attacker embeds Aero2 pages in an iframe to trick users.
Mitigations:X-Frame-Options: DENYon all responsesframe-ancestors 'none'in Content Security Policy
10. XSS (Cross-Site Scripting)
Threat: Attacker injects malicious scripts into pages.
Mitigations:- Content Security Policy restricts script sources to
'self' - React auto-escapes rendered content
- API responses use
default-src 'none'CSP - No inline scripts (except
'unsafe-inline'for styles, which is standard for CSS-in-JS)
11. Disabled User Access
Threat: Admin disables a user but they continue to access the system via existing sessions.
Mitigations:- Disabling a user immediately revokes all active sessions (proactive invalidation)
- Disabled check runs before every authenticated action as a defense-in-depth measure
Known Gaps (See Roadmap)
| Gap | Impact | Roadmap Item |
|---|---|---|
| In-memory rate limiting | Bypassable on cold start | Phase 1 #1 |
| No account lockout | Brute-force possible | Phase 1 #4 |
| No MFA | Single-factor only | Phase 2 #10-12 |
| Dynamic SQL for ORDER BY | Fragile (validated but string-interpolated) | Phase 7 #32 |
| No dependency scanning in CI | Vulnerable deps may ship | Roadmap #9 |
| Refresh token lifetime (30 days) | Wide window if stolen | Phase 5 #27 |
Security Contact
Report security vulnerabilities via the project's GitHub security advisory process. Do not open public issues for security bugs.