Skip to content

Threat Model: 0xj4f/genesis - Triple redundancy + code validation #41

@0xj4f

Description

@0xj4f

Final Validation - Threat Model

Security Review – Validation of the Draft Threat‑Model against the current codebase

Threat ID Verdict Evidence (file path + snippet) Comments
T001 – Credential spoofing (password theft / brute‑force) VALID app/services/auth_service.pyuser = authenticate_user(db, username=form_data.username, password=form_data.password)
app/utils/security.pydef verify_password(plain_password: str, hashed_password: str) -> bool:
The system authenticates solely on a username/password pair; no MFA or account‑lockout is implemented.
T002 – Token theft / replay VALID web/legacy/LoginForm.vuelocalStorage.setItem('access_token', result.access_token);
web/src/components/LoginForm.vuethis.login(result.access_token); // Store the access token in Vuex
Tokens are returned in the JSON response and stored in client‑side storage that is accessible to JavaScript, making them stealable via XSS or other client‑side attacks.
T003 – SQL Injection (tampering) INVALID No raw SQL strings are used. All DB access is performed through SQLAlchemy ORM methods such as db.query(User).filter(User.id == user_id).first(). The code never concatenates user input into SQL; therefore the described injection vector does not exist.
T004 – Profile tampering (unauthorised update) INVALID app/routes/profiles.py – all profile routes are under /profile/me/ and receive the current_user via Depends(oauth_authenticate_current_user).
app/services/profile_service.pydef update_profile_service(db: Session, user_id: str, profile_update: ProfileUpdate): uses the authenticated user’s ID.
No endpoint accepts an arbitrary user_id or profile_id; the service only updates the profile of the authenticated user.
T005 – Lack of audit logging (repudiation) VALID app/main.py – only logs “Creating tables…”, no request‑level logging anywhere else.
All route handlers contain no logger.info / audit‑trail statements.
Critical actions (login, token refresh, profile changes) are not recorded, impairing forensic analysis.
T006 – JWT secret disclosed in source VALID app/auth/auth.pySECRET_KEY = os.getenv("OAUTH_SECRET_KEY","0f2883258b3c2cb9e21f1bdc827eafb9b7ad5509bf37103f82a1abab9109c65a") A hard‑coded secret is compiled into the code and visible to anyone with repository access.
T007 – Development DB credentials in .env.example VALID .env.exampleMYSQL_DEV_USER=dev\nMYSQL_DEV_PASSWORD=devpassword\n...
app/database/session.py – defaults DATABASE_PASSWORD = os.getenv("MYSQL_DEV_PASSWORD","SECURE_PASSWORD")
Plain‑text credentials are committed to the repo and also baked as defaults, enabling DB access if the repo leaks.
T008 – No rate‑limiting on authentication endpoints (DoS / credential‑stuffing) VALID The project does not import or configure any rate‑limiting middleware (e.g., slowapi, starlette‑limiter). All /token, /users/* and /profile/* routes are unrestricted.
T009 – Unbounded request payload sizes (DoS) VALID No max_content_length or request‑size validator is set in FastAPI. The default allows arbitrarily large bodies, e.g., in app/routes/auth.py the /token endpoint accepts any form data size.
T010 – Disabled‑account token usage (EoP) INVALID app/auth/auth.pyif user.disabled: raise HTTPException(status_code=400, detail="User is deactivated") is executed for every request after token decoding. A disabled account cannot use a previously‑issued token; the check is enforced on each request.
T011 – Internal‑service token validation too permissive (EoP) VALID app/auth/auth.pydef oauth_authenticate_internal_service(...): extracts user_id and sub from the token without checking the user’s existence or disabled flag.
T012 – Unauthenticated user enumeration & data disclosure (IDOR) VALID (newly added) app/routes/users.py@router.get("/", response_model=list[User]) def get_users(...): return get_all_users_service(db)
@router.get("/{user_id}", response_model=User) def get_user_by_id(user_id: str, ...)
@router.post("/search", response_model=User) def search_user(request: UserSearchRequest, ...) – all three are not protected by oauth_authenticate_current_user.
Any client can list all users, retrieve any user by UUID, or search by e‑mail/username without authentication, leaking personal data.

Revised Executive Summary

The Genesis Identity Access Management API suffers from several high‑severity security weaknesses:

  • Hard‑coded secrets – the JWT signing key and development MySQL credentials are embedded in source files (app/auth/auth.py, .env.example).
  • Token handling – tokens are returned in JSON and stored in browser‑side storage (localStorage / Vuex), exposing them to theft and replay.
  • Missing audit logging – authentication, token refresh and profile modifications are not logged, preventing accountability.
  • No rate‑limiting or request‑size controls – the /token and other public endpoints can be abused for credential‑stuffing or resource‑exhaustion attacks.
  • Over‑permissive internal token validation – internal service endpoints accept any well‑formed JWT without verifying the associated user’s state.
  • Unauthenticated user enumeration – the /users collection, individual user look‑up (/users/{id}) and search endpoints are publicly accessible, leaking personal data.

These issues collectively give an attacker multiple paths to spoof identities, replay or forge tokens, enumerate user data, and launch denial‑of‑service attacks. Immediate mitigation actions are required (see consolidated mitigation ideas).


Consolidated Threat List (Validated)

ID STRIDE Consolidated Description DREAD (as reported)
T001 Spoofing Password theft or brute‑force enables an attacker to obtain valid credentials and log in as any user. 37 (High)
T002 Spoofing Stolen JWT access/refresh tokens can be reused to impersonate the victim. 39 (Critical)
T005 Repudiation Lack of audit logs for authentication, token refresh and profile changes prevents detection and forensic analysis. 30 (High)
T006 Information Disclosure JWT secret key is hard‑coded and visible in source, allowing token forgery. 43 (Critical)
T007 Information Disclosure Development MySQL credentials are stored in plain text in .env.example and as defaults, enabling DB access if leaked. 27 (Medium)
T008 Denial‑of‑Service No throttling on /token or login‑related endpoints permits credential‑stuffing and resource exhaustion. 36 (High)
T009 Denial‑of‑Service Unlimited request body size allows memory/CPU exhaustion attacks. 24 (Medium)
T011 Elevation of Privilege Internal‑service token validation does not verify user existence or disabled status, allowing crafted tokens to be accepted. 23 (Medium)
T012 (added) Information Disclosure / Tampering Unauthenticated /users, /users/{id} and /users/search endpoints expose full user records, enabling enumeration and data leakage. 34 (High) (estimated: Damage 9, Repro 7, Expl 8, Affected 7, Discover 3)

All other threats from the original draft (T003, T004, T010) were found invalid after code inspection and are omitted.


Critical Missing Issue (New Threat T012)

Evidenceapp/routes/users.py contains publicly exposed routes:

@router.get("/", response_model=list[User])
def get_users(db: Session = Depends(get_db)):
    return get_all_users_service(db)

@router.get("/{user_id}", response_model=User)
def get_user_by_id(user_id: str, db: Session = Depends(get_db)):
    user = get_user_by_id_service(db, user_id)
    ...

No Depends(oauth_authenticate_current_user) is applied, meaning anyone can list or retrieve arbitrary user records. This constitutes an information‑disclosure / IDOR vulnerability and has been added as T012.


Summary of Required Actions

  1. Secret Management – Move JWT secret and DB credentials out of source into a secure secret store; remove defaults.
  2. Token Storage – Issue tokens as HttpOnly + Secure cookies or enforce short‑lived access tokens with refresh‑token rotation; avoid client‑side storage.
  3. Audit Logging – Add structured request‑level logging (login attempts, token refresh, profile changes) to a central SIEM.
  4. Rate Limiting & Payload caps – Deploy a FastAPI middleware (e.g., slowapi) to limit auth endpoints and set a reasonable max_content_length.
  5. Hardening Internal JWT Validation – Enforce audience/issuer checks and verify the user’s existence/disabled status for all service‑to‑service tokens.
  6. Protect User Data – Require authentication (and appropriate authorization) on /users* endpoints; consider pagination and data minimisation.
  7. CORS Policy – Restrict origins to known front‑end domains instead of ["*"].

Implementing these mitigations will substantially reduce the overall risk profile of the Genesis IAM system.

Lead Threat Analyst Manager

Consolidated Threat‑Model Draft – Genesis Identity Access Management
(FastAPI + MySQL + Vue SPA – version 2026‑01‑19)


1️⃣ Executive Summary

The system provides user registration, authentication (username/password → OAuth2 Password flow) and profile management via a FastAPI backend backed by MySQL. A Vue.js single‑page application consumes the API. The API is internet‑facing, permits CORS from any origin, stores the JWT secret and development database credentials in a publicly visible .env.example, and lacks request‑size limits or rate‑limiting on authentication endpoints. Eleven distinct threats have been identified that span the full STRIDE spectrum; all three source reports describe the same set of threats, only differing in presentation. DREAD scores are taken from the two reports that provide them; the scores are consistent across those reports.


2️⃣ Threat Mapping Table

Canonical ID Original IDs (reports) STRIDE Merged Description DREAD (as reported)
T001 T001 (Report 1, 2, 3) S – Spoofing An attacker obtains a user’s username/password (via phishing, brute‑force, insecure storage, etc.) and logs in as the legitimate user. Damage 9, Repro 7, Expl 8, Affected Users 7, Discover 6 → Total 37 (High)
T002 T002 (Report 1, 2, 3) S – Spoofing A valid JWT access or refresh token is stolen (e.g., via XSS, insecure storage, logs) and reused to impersonate the user. Damage 9, Repro 8, Expl 8, Affected Users 7, Discover 7 → Total 39 (High)
T003 T003 (Report 1, 2, 3) T – Tampering Although the code uses SQLAlchemy ORM, crafted input or misuse of raw queries can lead to SQL injection, allowing data tampering. Damage 8, Repro 4, Expl 5, Affected Users 5, Discover 5 → Total 27 (Medium)
T004 T004 (Report 1, 2, 3) T – Tampering An attacker modifies profile information (given name, email, etc.) through insufficient authorization checks or by re‑using a stolen token. Damage 6, Repro 6, Expl 6, Affected Users 6, Discover 5 → Total 29 (Medium)
T005 T005 (Report 1, 2, 3) R – Repudiation Critical actions (login, profile changes, token refresh) are not logged, making detection and forensic analysis difficult. Damage 5, Repro 9, Expl 4, Affected Users 7, Discover 5 → Total 30 (High)
T006 T006 (Report 1, 2, 3) I – Information Disclosure The JWT secret key (OAUTH_SECRET_KEY) is hard‑coded and visible in source/.env.example, enabling token forgery. Damage 9, Repro 8, Expl 9, Affected Users 8, Discover 9 → Total 43 (Critical)
T007 T007 (Report 1, 2, 3) I – Information Disclosure Development MySQL credentials are stored in plain text in .env.example; if the repository is deployed or leaked, an attacker can connect to the database. Damage 8, Repro 4, Expl 5, Affected Users 6, Discover 4 → Total 27 (Medium)
T008 T008 (Report 1, 2, 3) D – Denial‑of‑Service No throttling on /token or login endpoints allows brute‑force password guessing and resource exhaustion. Damage 6, Repro 8, Expl 9, Affected Users 7, Discover 6 → Total 36 (High)
T009 T009 (Report 1, 2, 3) D – Denial‑of‑Service Endpoints accept unbounded JSON payloads, enabling memory/CPU exhaustion attacks. Damage 5, Repro 4, Expl 5, Affected Users 5, Discover 5 → Total 24 (Medium)
T010 T010 (Report 1, 2, 3) E – Elevation of Privilege oauth_authenticate_current_user validates the JWT before checking user.disabled; a still‑valid token for a disabled account can grant access. Damage 8, Repro 3, Expl 4, Affected Users 5, Discover 4 → Total 24 (Medium)
T011 T011 (Report 1, 2, 3) E – Elevation of Privilege oauth_authenticate_internal_service accepts any valid JWT without strict audience/issuer verification, allowing privilege escalation in internal service calls. Damage 8, Repro 3, Expl 4, Affected Users 5, Discover 3 → Total 23 (Medium)

If any DREAD component differed between the two scoring reports, the column would show a range (e.g., “Damage 8‑9”). All scores are identical, so a single value is shown.


3️⃣ Consolidated Mitigation Ideas

The following mitigations combine the recommendations from all three source reports; they are grouped by the threats they address but presented as a unified set of actions.

  1. Externalise and Protect Secrets

    • Store OAUTH_SECRET_KEY, MySQL credentials, and any other secrets in a vault or secure environment variables (AWS Secrets Manager, HashiCorp Vault, etc.).
    • Remove hard‑coded defaults from source; the application must fail to start if required secrets are missing.
    • Rotate the JWT secret regularly and consider using asymmetric keys (RS256) with a kid header to facilitate key rotation.
  2. Strengthen Authentication & Credential Handling

    • Enforce multi‑factor authentication (MFA) for privileged accounts.
    • Apply account lock‑out or exponential back‑off after a configurable number of failed login attempts.
    • Use a memory‑hard password hashing algorithm (e.g., Argon2id or PBKDF2 with high work factor) instead of only bcrypt.
  3. Secure JWT Storage and Lifecycle

    • Keep access tokens only in memory or in HttpOnly + Secure cookies; never persist them in localStorage or other browser‑accessible stores.
    • Shorten access‑token lifetimes (e.g., 5 minutes) and rotate/rotate refresh tokens on each use.
    • Implement a token revocation list keyed by the jti claim to allow immediate invalidation of compromised tokens.
  4. Implement Robust Audit Logging

    • Log every authentication event, token refresh, and profile modification with user ID, timestamp, source IP, and outcome.
    • Use structured (JSON) logging and forward logs to a central SIEM or log aggregation service (ELK, Splunk, etc.).
  5. Enforce Rate Limiting and Throttling

    • Apply a global rate limit (e.g., 5 requests / second per IP) on authentication‑related endpoints (/token, /users/*).
    • Use middleware such as slowapi or starlette‑limiter to enforce the limits and return HTTP 429 when exceeded.
  6. Validate Authorization on All Resource Operations

    • For profile CRUD, ensure the user_id extracted from the JWT matches the target resource; reject mismatches with 403.
    • Perform the user.disabled check before any further processing of the request, returning an error if the account is disabled.
  7. Harden Database Interaction

    • Disallow raw SQL strings; always use SQLAlchemy’s parameterised query APIs.
    • Enable the future flag and review the code for any direct text() usage.
    • Run static analysis tools (Bandit, sql‑fluff) in CI to detect unsafe queries.
  8. Prevent Information Leakage

    • Remove .env.example (or replace secret values with placeholders) from the repository and add it to .gitignore.
    • Ensure error responses do not expose stack traces, file paths, or internal configuration details.
  9. Limit Request Payload Size

    • Configure FastAPI/Starlette to reject bodies larger than a safe threshold (e.g., 1 MiB) using max_content_length or a custom request‑size validator.
  10. Strengthen Internal Service Token Verification

    • Require strict aud and iss validation for tokens used by internal services.
    • Prefer asymmetric signing (RS256) for service‑to‑service JWTs and keep separate key pairs for internal vs. external tokens.

4️⃣ Notes for Security Reviewer

  • Ambiguities / Open Questions

    • The exact order of checks in oauth_authenticate_current_user (disabled‑account bypass) should be verified in code; the report assumes the token is validated before the disabled flag is examined.
    • The internal‑service token validation (oauth_authenticate_internal_service) does not currently enforce audience/issuer; confirm whether any additional claims are expected by consuming services.
    • The DREAD scores for each threat come only from Reports 2 and 3; Report 1 provides only likelihood/impact. No discrepancies were found, but the reviewer should ensure the scoring aligns with the organization’s risk‑scoring policy.
  • Disagreements Between Reports

    • None. All three drafts enumerate the same eleven threats with identical identifiers, descriptions, and (where provided) DREAD numbers.
  • Items Needing Code Validation

    • Verify that the JWT secret is indeed hard‑coded in the production configuration and that .env.example is packaged with the image.
    • Confirm that no explicit request‑size limits are set in FastAPI/Starlette (max_content_length or equivalent).
    • Check that CORS is deliberately set to * and that this is acceptable for the deployed environment.
    • Review the profile‑service implementation to ensure the user_id from the token is enforced as the sole identifier for profile operations.
    • Ensure that audit‑logging statements are present (or absent) for the actions mentioned in T005.
  • Suggested Validation Activities

    • Run a static‑analysis scan focused on hard‑coded secrets and raw SQL usage.
    • Perform a penetration‑test that attempts credential stuffing and token replay attacks against the /token endpoint to confirm rate‑limit enforcement.
    • Execute automated security tests that attempt to modify a disabled account’s data and invoke the internal service endpoint with a forged JWT.

Prepared by: DevSecOps Engineer – STRIDEGPT
Date: 2026‑01‑19

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions