Scope public API endpoints to caller visibility (GHSA-6ghm-wf22-pvx5)#367
Scope public API endpoints to caller visibility (GHSA-6ghm-wf22-pvx5)#367jbrooksuk wants to merge 3 commits into
Conversation
The public JSON API `index`/`show` endpoints never applied the `HasVisibility` scopes that the web UI and RSS feed use, so anonymous callers could read incidents, metrics and component groups marked `authenticated`-only or `hidden`. - Scope Incident, Metric and ComponentGroup index/show to the caller's visibility, returning 404 for out-of-scope records on show. - Scope Component index/show by the visibility of its group (components inherit visibility from their group; ungrouped stay public, matching the status page). Hide disabled components by default with an opt-in `enabled` filter; show 404s disabled components. - Gate the nested IncidentUpdate and MetricPoint controllers on their parent's visibility. - Fix ComponentGroupFactory using the wrong enum for `visible`, which defaulted groups to `authenticated` instead of `guest`. - Add API visibility regression tests across all affected endpoints. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…includes The visibility scoping resolved callers via the default guard, which never sees bearer tokens on the unauthenticated read routes, so authenticated API consumers were served guest-scoped data. Includes could also bypass the scoping: components?include=incidents revealed hidden incidents, and incidents/schedules?include=components.group revealed hidden groups. Disabled components are now consistently hidden from guests and readable by authenticated callers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4efc0e8 to
3b49c3f
Compare
|
Rebased onto 1. Bearer-token callers were treated as guests (critical). The controllers resolved the caller via 2. Relationship includes bypassed the scoping. 3. Disabled components were inconsistently guarded. Verified as already covered / not applicable: schedules have no Flagged for a separate decision: Full suite: 663 passed. PHPStan and Pint clean. 🤖 Generated with Claude Code |
…lisions The include-leak tests matched included resources by name, which fails when faker generates a component name equal to the hidden group's name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
The public JSON API
index/showendpoints never applied theHasVisibilityscopes that the web status page and RSS feed use. Any unauthenticated caller could list and read incidents, metrics and component groups markedauthenticated-only orhidden. Fixes GHSA-6ghm-wf22-pvx5 (CWE-862, CVSS 7.5).What changed
index+show: apply->visible(auth()->check());shownow returns 404 for out-of-scope records instead of leaking them.index+show: components have no visibility column — they inherit it from their group. Scoped by group visibility (whereNull('component_group_id')OR group is visible), so ungrouped components stay public, matching the status page. Also hidesdisabledcomponents by default with an opt-infilter[enabled]=false;show404s disabled components.IncidentUpdate,MetricPoint): gated on the parent's visibility so children of hidden/auth-only parents 404.ComponentGroupFactory: fixed a latent bug wherevisiblewas set fromComponentGroupVisibilityEnum::expanded(value0), which under theResourceVisibilityEnumcast meansauthenticated. Default is nowguest.guest; authenticated seesauthenticated+guest;hiddennever; ungrouped components stay public; disabled hidden-by-default but reachable via filter; nested children respect parent visibility.Not affected
Schedule/ScheduleUpdateControllerhave no visibility concept and are unchanged. The advisory's inclusion ofcomponents/schedulesin the "identical pattern" list is partially inaccurate: Schedule has novisiblecolumn, and Component's leak is via its group rather than a column of its own.Verification
Warning
Draft: this is a public PR for an unpatched advisory, so the diff discloses the vulnerability. Coordinate with the release/advisory before marking ready.