Unauthenticated server actions in lookup-actions.ts leak internal roster PII
Split from PLUTO-632 (audit-pluto-roleless finding, 2026-07-30): getLookupOptions, getActiveComisionLabels, getJtpsForCurrentPeriodoComision, getAdjuntosForCurrentPeriodoComision, getTitularesForComision in src/lib/lookup-actions.ts have ZERO identity check -- callable by any visitor with no session at all (Next.js Server Actions are directly POST-callable once the action ref is in the client bundle). Called on mount/comision-select by src/app/solicitar-acceso/page.tsx, which itself only gates render on 'any session with an email' (not genuine-Google) -- render is inert since the real mutation submitAccessRequest independently re-checks isGenuineGoogleUser server-side, but the 5 lookup actions bypass even that. Exposure: current-period comision names + JTP/adjunto/titular staff display names (who supervises which comision) -- internal roster PII, not clinical/document data, no write path. Fix: require a valid Supabase session (getCurrentUser() non-null) on all 5 actions before returning data -- do not require a role/users row (must still work for a genuine-Google user awaiting human match at /solicitar-acceso, per admission-by-design). Class-A (touches an auth-gate surface) -- pre-push audit diff review + PTD required; audit-pluto-ca backlog is separate, use a cold-brief when it returns or flag PM for review against the invariant note if urgent.
Questions
Activity
-
escalated to top priority per pmmaster (2026-07-30 02:15): anonymous-callable on prod w/ 398 live users, outranks terra's finding tonight — do not let this queue
-
priority 2 -> 1 (urgent), pmmaster escalation: highest-priority live finding of the night, reachable now by anyone with no account
-
Fixed 8c5d23c/v2.22.16: session gate added to all 7 use-server exports in lookup-actions.ts (fix covered 7, not the 5 originally named — getLookupOptionsByGrupos/getLookupOptionById were also unguarded), tipoDocumento sessionless carve-out preserved for the HMAC resume-link flow. Test coverage a4b2f74/v2.22.17 (10 green, pins the carve-out against future removal). Class-A PTD PASS: live version match, deploy READY+aliased, build clean, zero runtime errors 1h. Coverage gap noted: carve-out path itself not exercised live (no valid signed link to probe with) — covered by the new test instead.
-
REOPENED: audit-pluto-ca retro review (audit-pluto-ca-ms73b04vu8bc) found a real regression on the shipped fix -- requireAuthForAction is the mutation guard and rejects isViewAs; using it on read-only lookup actions breaks view-as render paths (/practicas/[id], /mi-cursada/[id]). BLOCK 8c5d23c + BLOCK a4b2f74 (test pins wrong abstraction, same fix). Already routed direct to coder-pluto-cc by audit (audit-pluto-ca-ms739zc2rowi). Needs a read-safe session guard distinct from the mutation guard.
-
status=blocked
-
correcting accidental blocked-status keystroke from my prior command; actual state: reopened due to audit regression, not blocked -- coder-pluto-cc already has the BLOCK routed directly and can fix without unblocking from me
-
Re-fixed 90a3f2e: read-safe session guard (distinct from requireAuthForAction mutation guard) restores view-as render on /practicas/[id], /mi-cursada/[id]. audit-pluto-ca PASS 90a3f2e -- guard semantics + anon/normal/view-as tests correct, 193 green, tsc clean, 8 expected falsification failures against old guard, PTD live v2.22.19 clean build/runtime. Closes both 8c5d23c and a4b2f74 blockers.