{
  "feature_id": "F-006",
  "agent": "security",
  "verdict": "APPROVED",
  "threat_model": [
    {
      "vector": "SQL injection",
      "result": "mitigated",
      "evidence": "Every query parameterized ($n). The only dynamic SQL (profile upsert, address update) builds SET clauses from a hardcoded column whitelist; user input only flows into parameter values."
    },
    {
      "vector": "Privilege escalation (client sets own role)",
      "result": "mitigated",
      "evidence": "register/login schemas accept only email+password; no route writes identity_users.role. Role is returned from DB values, never echoed from input. DB CHECK constraint limits role to customer|admin."
    },
    {
      "vector": "Broken access control / IDOR",
      "result": "mitigated",
      "evidence": "Each users route runs authenticate -> requireOwnerOrAdmin before data access; address repository scopes every query by user_id, so a valid foreign addressId is unreachable. Integration tests prove cross-user reads and mutations all return 403."
    },
    {
      "vector": "Resource existence enumeration",
      "result": "mitigated",
      "evidence": "Authorization (403) is evaluated before existence checks (404) for non-owners, so a stranger cannot learn whether another user's profile exists."
    },
    {
      "vector": "Stale authorization (demotion/promotion)",
      "result": "mitigated",
      "evidence": "Session authenticator resolves role from identity_users on every request; role changes apply immediately without re-login, and no role state is trusted from the client."
    },
    {
      "vector": "Session security",
      "result": "unchanged from F-005",
      "evidence": "Opaque token in HttpOnly/SameSite=Lax cookie, SHA-256 hash stored server-side, expiry + revocation enforced in SQL. Cookie plugin moved to app root (cross-module), same policy."
    }
  ],
  "dependencies_added": [],
  "notes": "No new npm dependencies; spec/tech.md unchanged. The 403-vs-404 ordering is correct for anti-enumeration. GET /users admin list returning only profiled users is not a security issue (admin-only surface).",
  "evidence": "npm run test:integration: 22 passed including forged-cookie 401, cross-user 403 battery, and logout revocation regression"
}
