basquetWi + New ticket
pluto PLUTO-27

Pluto P3: getCurrentPeriodoId + getComisionesForCurrentPeriodo no auth guard — comision enumeration

Done low cpcoder-pluto-cc

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 2026-06-10
  • wi-cli-venus assigned · 7w ago
    coder-pluto-cc
  • wi-cli-venus completed · 7w ago
    Shipped v2.23.61. WI PREMISE STALE: it named getCurrentPeriodoId and getComisionesForCurrentPeriodo; neither exists - both were removed in ad6db96 when completar-asignacion moved behind fn_getStudentAssignmentBootstrap. A grep-and-close would have read as 'already fixed'. The defect was real and LIVE at the successor site, which shares no name with the old one: getPeridosForSelector, getComisionesForPeriodo and isPeriodoValid in administrar-actions.ts had no guard of any kind. Every export of a 'use server' file is an independently POST-callable endpoint for any caller, authenticated or not, regardless of which page imports it (PLUTO-635) - so unguarded these enumerate every periodo and every comision name in the catedra to an anonymous POST. Invisible from the app side precisely because it was never reachable there: all in-app callers are RSC pages under (protected)/administrar already running requireCap('manageRoster'). FIX: new requireCapForRead(cap) in auth-guard.ts - exactly the composition requireAuthForRead's own docstring points at - applied to all three at the same cap the pages use, so no legitimate caller changes behaviour. Read variant, NOT requireCapForAction: that one is the write chokepoint and throws under view-as, and these run during RSC render, so it would 500 an admin viewing as another user (the PLUTO-638 regression class). Denial shape, message and logAuthz action mirror requireCapForAction so the classifier cannot distinguish them. 9 tests: anonymous denied, authenticated-without-cap denied, and view-as still served - the last is the one that would otherwise rot. The two denial cases also assert the pool was never touched, since a denial after the query is not a denial. 769/56 green, tsc clean. LIMIT + FOLLOW-UP: a crude scan for unguarded exports across all 'use server' files returns a long list beyond these three (queries.ts alone has ~110 exported reads). The scanner is unreliable - it cannot see guards enforced at the caller or via a pre-authorized user argument, which is the documented pattern for scope-resolved reads - so I am NOT claiming those are defects and have not touched them. Filed for a proper audit-lane sweep rather than dropped.
task
2026-06-10 by wi-cli-venus
7w ago
2026-08-22 14:34