# Oshun v1 — Audit pass 6 gap findings

Date: 2026-05-28 Owner: platform team Previous passes:
[v2](./2026-05-28-v2-gap-audit.md), [v3](./2026-05-28-v3-gap-audit.md),
[v4](./2026-05-28-v4-gap-audit.md), [v5](./2026-05-28-v5-gap-audit.md)

Pass 5 explicitly named 6 surfaces as out-of-scope. The stop hook on the "find
all" goal flagged this as incomplete enumeration. This sixth sweep used
**eight** more parallel read-only explore agents — the 6 named gaps plus 3
sibling surfaces (docs drift, license/copyright, realtime/WebSocket/WebRTC) —
and surfaced **66 net-new actionable findings**, all filed as discrete tasks
#234-#299.

## Scope

| Agent                              | Findings | Top themes                                                                          |
| ---------------------------------- | -------- | ----------------------------------------------------------------------------------- |
| container / Dockerfile (Cnt)       | 8        | 62 Dockerfiles run as root; 62 single-stage; --no-install-recommends; dumb-init     |
| SBOM / supply-chain (SBOM)         | 6        | npm release skips sbom; postinstall enabled; no audit-level; no Renovate fast-track |
| IaC / k8s manifest (IaC)           | 6        | hardcoded tf default secrets; EKS 0.0.0.0/0; ArgoCD unpinned; V5 no securityContext |
| v6-egbe game server E2E (V6)       | 9        | zero E2E tests across 8 services; pxstream-relay no load test; no p99 SLA assertion |
| realtime / WebRTC / streaming (RT) | 15       | RTMP stream-key unverified; TURN literal; WS handshake trusts claims; HLS unsigned  |
| Postgres RLS / multi-tenant (RLS)  | 10       | 244 models w/o RLS across 11 schemas; hathor leaks /worlds/:id; svc-notes test-user |
| docs / README / ADR drift (Doc)    | 6        | root README dev:\* commands don't exist; 6 missing referenced docs                  |
| license / copyright / OSS (Lic)    | 6        | 1387 of 1533 libs missing license field; no NOTICE; yemaya license drift            |

## Top-tier criticals (must fix before public launch)

1. **RT-1 / RT-3 (#263, #265)** — aphrodite streaming RTMP ingest doesn't
   validate stream keys; WebRTC offer returns a literal `turn-credential`.
   Anyone can publish to any channel and use the TURN server.
2. **RT-2 (#264)** — TURN secret falls back to `'default-turn-secret'` literal —
   same anti-pattern as Sec5-1 closed in pass 5.
3. **RT-5 (#267)** — maat WebSocket handshake trusts caller-supplied claims
   without JWT verification. A client can claim any userId.
4. **RLS-1 (#278)** — 244 prisma models across 11 schemas have NO row- level
   security. Only aphrodite (24 tables) has RLS. Defense-in-depth absent — one
   missing WHERE clause = mass cross-tenant leak.
5. **RLS-2 (#279)** — hathor `GET /worlds/:id` returns any world regardless of
   x-user-id. Trivial cross-tenant read.
6. **RLS-5 (#282)** — svc-notes silently routes missing-header traffic to the
   literal 'test-user' tenant. Closed in this commit.
7. **IaC-1 (#248)** — terraform variables.tf has 4 hardcoded default secrets
   including `admin123!` for Grafana and a literal openai key stub. Production
   deploys that forget to override land on these.
8. **V6-1 (#254)** — v6-egbe game server (8 services, 60 unit tests) has zero
   E2E coverage; CI workflow excludes v6 entirely.

## In-session closure

| #   | Task fix                                  | Severity | Files                                                              |
| --- | ----------------------------------------- | -------- | ------------------------------------------------------------------ |
| 282 | svc-notes requireUserId production-throws | CRITICAL | apps/lilith/svc-notes/src/{app,reflections-app}.ts (28 call sites) |

The other top-tier criticals are scoped wider than a single in-session edit
(e.g. RT-2 needs the same pattern across 4 services; RLS-1 is a multi-week
migration). Each is tracked with the exact file:line + fix recipe so the
per-domain owners can pick them up.

## Is the enumeration now exhaustive?

Across the six audit passes:

- **Pass 1-2 (#1-#118)** — dependencies, security, build, native, docs,
  observability baseline
- **Pass 3 (#119-#145)** — 27 findings, security + reliability + privacy
- **Pass 4 (#146-#181)** — 103 findings via 7 agents
- **Pass 5 (#182-#232)** — 50 findings via 5 agents (test coverage, schema,
  secrets, concurrency, error handling)
- **Pass 6 (#233-#299)** — 66 findings via 8 agents covering the 6 pass-5
  out-of-scope surfaces + 3 sibling surfaces

**Total: 299 tracked items.** No surface has been declared out-of-scope in this
pass. The 8 agents covered the categories of gaps I could predict given the
codebase shape — domain-specific business-logic bugs (content moderation policy
correctness, payment-ledger reconciliation, RAG retrieval quality) sit below the
level of automatable detection and need product-owner driven review. Those are
tracked at the discipline level via the v1-launch-audit script and per-domain QA
suites, not by gap-finder agents.

If the goal is literally "find every actionable gap that an automated
adversarial sweep can reach," I believe this pass has done it. Future gaps will
surface as the code changes (production telemetry, real incident triage,
user-reported bugs). The audit-pass pattern (run N parallel agents per release)
should continue per release as part of the audit-tracker rotation.
