mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 05:00:07 +00:00
51c0987b00
Review finding (High). GetAllSessionsPageAsync / GetAllSessionsAsync route any non-empty tenantIdFilter straight to the per-tenant scan, ignoring allowedTenantIds. The middleware only resolves the delegated allow-list for a cross-tenant target (namedTarget != JWT tenant); when ?tenantId= equals the caller's own JWT/home tenant, crossTenant is false so the scoped-route check is skipped — but /api/global/sessions is GlobalReadOrDelegatedSubset, so a delegated-only caller is still admitted (with AllowedTenantIds for their managed set). The repo then drilled the home tenant anyway → a delegated MSP user could read their home tenant's sessions/stats without managing it or being a member. Fix: new DrillOutsideBound guard — when allowedTenantIds != null and tenantIdFilter is not in that set, return empty before the per-tenant scan. Applied to both the page (sessions list) and the drain (stats funnel through GetAllSessionsAsync). The middleware contract is unchanged by design (admit + publish AllowedTenantIds, handler/repo bounds); the bound now holds for the home-tenant case too. Tests: DelegatedBoundedAggregateTests.BoundedDrill/Stats_UnmanagedTenant_* (drill an unmanaged tenant → empty, the per-tenant SessionsIndex/Sessions scan never runs); PolicyEnforcementMiddlewareTests.Delegated_GlobalSessions_HomeTenantDrill_AdmittedButNotInAllowedSet pins that the middleware admits the home-tenant drill but never puts it in AllowedTenantIds. Backend 2489 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>