Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

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_use claim) 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=Strict on 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:action granularity
  • 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: DENY on all responses
  • frame-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)

GapImpactRoadmap Item
In-memory rate limitingBypassable on cold startPhase 1 #1
No account lockoutBrute-force possiblePhase 1 #4
No MFASingle-factor onlyPhase 2 #10-12
Dynamic SQL for ORDER BYFragile (validated but string-interpolated)Phase 7 #32
No dependency scanning in CIVulnerable deps may shipRoadmap #9
Refresh token lifetime (30 days)Wide window if stolenPhase 5 #27

Security Contact

Report security vulnerabilities via the project's GitHub security advisory process. Do not open public issues for security bugs.