Skip to content

Threat Model: 0xj4f/genesis  #44

@0xj4f

Description

@0xj4f

Final Validation - Threat Model

Validated Threat‑Model (only ✅ VALID / ⚠️ PARTIAL entries)


Executive Summary (rewritten)

Scope FastAPI‑based IAM service with a Vue 3 front‑end. Users register, authenticate via the OAuth2 password flow, receive JWT access (≈30 min) and refresh (≈7 days) tokens, and manage a personal profile stored in MySQL.
Key Findings 10 concrete threats have been validated in the current code. Three are critical – a hard‑coded JWT secret, a hard‑coded default DB password, and client‑side storage of JWTs in localStorage. Four are high‑priority – unrestricted CORS, missing audit logging, unauthenticated user‑enumeration, and lack of rate‑limiting. The remaining three are medium (debug prints leaking data, email‑uniqueness race, missing authorization on user‑lookup).
Overall Risk HIGH – exploitation can lead to full account takeover, data exfiltration, and complete system compromise.
Immediate Recommendations 1️⃣ Externalise & rotate the JWT secret (use a secret manager; migrate to asymmetric RS256). 2️⃣ Remove the hard‑coded MySQL password – require a secret from a protected source. 3️⃣ Stop storing JWTs in localStorage – use httpOnly Secure cookies or in‑memory storage. 4️⃣ Lock down CORS to the known front‑end origin(s) and disable allow_credentials unless required. 5️⃣ Add audit logging & rate‑limiting, and enforce proper authorization on all user‑lookup endpoints.

Consolidated Threat Mapping (validated)

Canonical ID STRIDE Description (merged) DREAD Verdict Evidence
C1 Spoofing The JWT signing key (SECRET_KEY) is hard‑coded with a default value. An attacker who discovers the secret can forge arbitrary access / refresh tokens and impersonate any user (including admin). 22 ✅ VALID app/auth/auth.py – line: SECRET_KEY = os.getenv("OAUTH_SECRET_KEY","0f2883258b3c2cb9e21f1bdc827eafb9b7ad5509bf37103f82a1abab9109c65a")
C2 Spoofing JWT tokens are stored in the browser’s localStorage (both legacy and current Vue components). Any XSS can read the tokens and hijack the session. 22 ✅ VALID web/src/components/LoginForm.vuelocalStorage.setItem('access_token', result.access_token);
web/src/components/LoginForm.vuelocalStorage.setItem('refresh_token', result.refresh_token);
C3 Tampering CORS is configured with allow_origins=["*"] and allow_credentials=True, allowing any origin to make authenticated requests with a victim’s JWT (CSRF‑style attacks). 21 ✅ VALID app/main.pyorigins = ["*"] and allow_credentials=True in CORSMiddleware setup
C6 Repudiation No immutable audit trail is kept for authentication events, token refreshes, profile changes, or user deletions, making it impossible to prove who performed which action. 16 ✅ VALID The code contains only print statements (e.g., in app/auth/auth.py) and no calls to a logging/audit facility.
C7 Information Disclosure Public endpoints (/users/{user_id} and /users/search) are accessible without authentication, allowing anyone to enumerate existing accounts. 22 ✅ VALID app/routes/users.py@router.get("/{user_id}") and @router.post("/search") have no Depends(oauth_authenticate_current_user)
C8 Tampering The email column is unique only at the DB level; the API checks for duplicates but does not protect against race conditions, so concurrent requests can trigger an integrity error that is exposed to the client. 14 ✅ VALID app/services/user_service.pyvalidate_existing_user checks email/username before create_user_db; DB column email is marked unique=True in app/models/user_db_model.py.
C9 Information Disclosure Debug print statements log full JWT payloads, usernames and DB objects to stdout; logs may be readable by unauthorized parties, leaking sensitive data. 17 ✅ VALID app/auth/auth.pyprint(f"token: {token}"), print(token), print(username), print(f"db user: {user}")
C10 Denial of Service No rate‑limiting or brute‑force protection is applied to the /token and /users endpoints, allowing attackers to flood these endpoints with unlimited requests (credential‑stuffing, DoS). 22 ✅ VALID No import of a rate‑limiting library (e.g., slowapi) and no middleware enforcing request caps.
C11 Elevation of Privilege Endpoints that retrieve user data (/users/{user_id} and /users/search) do not verify that the caller is authorised to view that specific user, allowing any authenticated (or unauthenticated) requester to read another user’s personal information. 17 ✅ VALID Same evidence as C7 – missing oauth_authenticate_current_user dependency on these routes.
C12 (new) Spoofing / Information Disclosure The MySQL connection uses a hard‑coded default password (SECURE_PASSWORD) when the environment variable is not set, exposing the DB to credential leakage and potential unauthorised access. 23 (critical) ✅ VALID app/database/session.pyDATABASE_PASSWORD = os.getenv("MYSQL_DEV_PASSWORD", "SECURE_PASSWORD")

Threats C4 (Stored XSS) and C5 (Verbose authentication errors) were invalid because the API returns generic JSON errors and never renders user‑supplied data as HTML. They have been omitted from the final list.


Additional Missing Threat (added)

Canonical ID STRIDE Description DREAD Evidence
C12 Spoofing / Information Disclosure Hard‑coded default MySQL password (SECURE_PASSWORD) in app/database/session.py can be used by an attacker who gains access to the source or deployment environment to connect to the database. 23 app/database/session.pyDATABASE_PASSWORD = os.getenv("MYSQL_DEV_PASSWORD", "SECURE_PASSWORD")

End of validated threat‑model.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions