Pluto IDOR: createNotification + markComentarioNotificationsRead unauthenticated, client-forgeable userId
audit-pluto-cc PLUTO-529 pass-2 bonus security finding: notification-actions.ts createNotification:16 + markComentarioNotificationsRead:90 are exported from a 'use server' module, do bare pool.query with a caller-supplied userId and ZERO auth guard -> directly client-callable with a FORGED userId (IDOR-class: spoof-create notifications for arbitrary users / mark another user's notifications read). Also no try/catch so real DB errors go unlogged. Fix must close the direct-client-call vector WITHOUT breaking legitimate internal fan-out (createNotification is the post-commit fan-out primitive, legitimately notifies OTHER users from admin flows). Investigate the call graph first. Class-A (auth surface) -> audit pre-impl ping + diff review + PTD.
Questions
Activity
-
Scope expanded 2->5 fns (PM call): coder call-graph found 3 more identical latent IDOR (getUnreadCount, getNotifications, hasUnreadComentarioPing — READ-only, lower sev: leak another user's unread count/notif list) sharing the same 'use server' caller-supplied-userId pattern. Fix = de-action all 5 into new non-'use server' notification-core.ts (all callers server-side, grep-confirmed → behavior-preserving) + try/catch->logCaughtError. One module move, one deploy closes the class. markRead/markAllRead excluded (PLUTO-529 guard-escape hold).
-
IDOR class closed: 5 notification helpers (2 write + 3 read) taking a caller-supplied userId were exported from a 'use server' module -> client-forgeable. De-actioned verbatim into notification-core.ts (leave the server-action RPC registry -> no client entry point). Writes now try/catch->logCaughtError. Behavior-preserving (all callers server-side), not widened. SHA b66e1ff v2.4.1, audit PASS + PTD all-green.