# 06 — SECURITY POSTURE & THREAT MODEL Generated 2026-07-05 · prod arm64-5ee0ae12002f · regenerated after wipe > snapshot 2026-07-05 · refreshed SEC-/AUTH- board statuses from `nc-agent-ops/board/issues.json`. Keep alongside the ledgers in `reports/`. ## Security stack (how it works) - **AuthN:** NextAuth v5, Credentials only (email+bcrypt). OAuth Google+Apple landed (AUTH-0807 Deployed); Facebook removed (AUTH-0813). Sessions: `createUserSession`/`ensureSessionActive` + server-side `UserSession` (`src/lib/auth/sessions.ts`). TOTP-2FA done (AUTH-0811). - **AuthZ (admin):** `requireAdmin()`/`isAdmin()` (`src/lib/auth/rbac.ts`) → `ADMIN_EMAILS` allowlist (csv, lowercase), **fail-closed deny-all if unset**. Prod: `admin@wool2.online,_@wool2.online`. Systemic hardening SEC-0308 (Deployed): `/api/admin/**` middleware + ESLint `requireAdmin` rule. - **Ownership (multi-tenant):** resources filtered by owner `userId` inline (`where:{ id, userId }`); no shared owner-guard helper. SSRF guard `assertPublicHttpUrl` (loopback/link-local/169.254/ULA block + `redirect:manual` + DNS re-check). - **Economy integrity:** server-authoritative economy (`src/lib/economy/*`) + `Transaction @@unique([userId, reference])` + `LedgerEntry.idempotencyKey @unique` — replay/mint guards. - **NO global `middleware.ts`** — every route self-guards (risk: a new route defaults OPEN). ## Threat model (boundaries, outside→in) 1. Anon → public share/embed/webhooks/cron/health. 2. Logged-in (own tenant). 3. Cross-tenant (IDOR). 4. Logged-in → admin (escalation). 5. App → server (RCE/secrets/DB). 6. App → downstream (LLM/TTS cost-abuse, social-API, SSRF). ## Audit status — SEC-/AUTH- board (2026-07-05 live) **108 tickets total** (70 SEC-prefixed + others). | Status | Count | Meaning | |---|---|---| | Owner Accepted | 46 | closed + owner-signed-off | | Deployed | 46 | fixed + live on prod (awaiting owner acceptance) | | Rejected by Lead | 7 | dup/invalid/superseded | | Parked | 4 | AUTH-0801 (epic), AUTH-0808 (invite-gate), AUTH-0812 (real ToS), **SEC-0310 (iMessage webhook fail-open)** | | Dev WIP | 3 | SEC-0253/0254 (unauth transcription), SEC-LOGIN-THROTTLE-LOCKOUT | | Lead Review | 1 | SEC-ENV-BOOT-FAILCLOSED | | Intake | 1 | SEC-ECONOMY-EPIC-SERVER-AUTHORITATIVE (umbrella) | **Open (non-Deployed, non-Accepted): 16.** = the Parked/Rejected/Dev-WIP/Lead-Review/Intake rows above. ### What's closed & verified live (~92 Deployed+Accepted) Video-pipeline IDOR family (0241/0242/0243/0264), clipper SSRF (0244), admin auth-bypass (agents/playwright/lighthouse 0295/0296/0297), set-tier priv-esc (0260), secret-leaks (0245/0259/0273/0286/0289), cost-DoS on paid compute (0265–0271, 0301/0305/0306), path-traversal (0249/0285), economy mint/replay (SEC-ECONOMY-* + IDEMPOTENCY-UNIQUE), RAG authZ (0166/0167/0234), realtime identity (0240), CSRF (AUTH-0722), registration anti-fraud epic (AUTH-0802..0811). Whole admin surface: 0 anon 200. ### Still-open / owner-facing - **SEC-0310 (Parked, P-watch):** iMessage/BlueBubbles webhook fail-open when `BRIDGE_SECRET` unset → unauth 200; Signal same latent. **Only live-open auth gap** per 07-03 hardening review. - **SEC-ENV-BOOT-FAILCLOSED (Lead Review):** process must refuse to boot if required secrets unset. - **SEC-0253/0254, SEC-LOGIN-THROTTLE-LOCKOUT (Dev WIP).** - **SEC-ECONOMY-EPIC-SERVER-AUTHORITATIVE (Intake):** consolidate the whole credit-class server-authoritative. - Open to owner: real ToS/Privacy flip (AUTH-0812; mechanics `src/lib/legal/syntheticFinalDocs.ts`, currently synthetic/not-for-publication), Apple Dev account. ## System risk #1 — SOURCE/PROD DRIFT Fixes live on prod but not in main/feature source. Localized (steward cherry-pick over live holds fixes), but a direct main-deploy = regress. Ticket `OPS-DRIFT-RECONCILE`. **Rule: until reconcile, deploy only steward-on-live.** This passport's 05 reflects SOURCE — a "public/unauthed" row may be hardened on prod. ## Verification lesson `400` (validation) ≠ closed. Only valid-shape unauth → **401/403/404-with-guard** = closed. AuthN ≠ AuthZ (IDOR needs 2 accounts). Deployed ≠ enforcing (verify guard wired). See 09. ## Zones (do NOT touch in audit/fixes) - **VOICE/telephony = Codex zone** (SIP/gateway, ports 9091/9092, `webhooks/telnyx`, `*-call/*`, `meeting-rooms/*`). Flag only. - **FC / deep-research = parked** (do not dispatch). ## Pointers Full findings: `reports/SECURITY-AUDIT-FINDINGS-LEDGER-20260702.md` · fix-pack `SECURITY-P0-FIX-PACK-20260702.md` · independent verify `NC-SECURITY-INDEPENDENT-VERIFICATION-20260702.md` · Codex `CODEX-SECURITY-AUDIT-FINDINGS-20260702.md`. Live DoD map: `nc-agent-ops/board/dod-endpoint-map.json`.