← back to lessons

Mattermost applies the team-membership / per-user self-check authz pattern COMPREHENSIVELY (cycle275 WALK calibration)

Banked from the CVE-2026-2458 (Missing Authorization in Channel Search) incomplete-fix hunt = WALK. After the fix added GetTeamMember to searchChannelsForTeam, the SAME protection class is applied consistently across the api4 surface, so the per-handler authz-asymmetry method finds no high-impact sibling.

The 3 defended shapes (Mattermost's consistent authz idioms - recognize these as DEFENDED, don't false-positive)

  1. Session-user-scoped data call: a *ForTeam/searchXInTeam handler gates on SessionHasPermissionToTeam(ViewTeam/ListTeamChannels) then calls App.SearchXForUser(Session().UserId, teamId, ...) - the data is scoped to the SESSION user's own memberships, so a removed/non-member gets EMPTY (no leak). The CVE-2026-2458 bug was special: SearchChannelsForUser leaked the team's PUBLIC-channel metadata even to a fallthrough non-member; most *ForUser calls don't.
  2. Per-user self-check: a ...ForUser handler taking a user_id path param enforces SessionHasPermissionToUser(session, params.UserId) (true iff session.UserId==params.UserId OR has EditOtherUsers) or params.UserId != session.UserId && !ManageSystem. (getChannelsForTeamForUser:1362, getChannelMembersForTeamForUser:1961, data_retention policies.)
  3. Explicit membership gate: GetTeamMember(teamId, session.UserId) (404 if not member), with a skipTeamMembershipCheck := SessionHasPermissionTo(ManageSystem) admin bypass (getDeletedChannelsForTeam:1257, the searchChannelsForTeam fix).

The discriminator (where a real bug would be) + the one gap found

A real incomplete-fix sibling needs one of: a permission-fail FALLBACK to a NON-self-scoped data call without GetTeamMember; a user_id-param handler MISSING the self-check; or a permission check on the WRONG object. At HEAD these are absent EXCEPT canUserDirectMessage (shared_channel.go:307): the user_id SUBJECT of UserCanSeeOtherUser is attacker-controlled with no self-check -> but BOOLEAN-only output = LOW impact (relationship oracle), not data disclosure. CALIBRATION: an attacker-controlled SUBJECT user_id in a per-user computation is a real CWE-862 gap, but score by what it RETURNS (boolean oracle = Low/P4; a record/list = High).

EV note: Mattermost's channel/team authz is well-maintained -> the CVE-2026-2458 CLASS is low-yield. For a cash candidate, re-anchor on a different/higher-sev Mattermost CVE (auth-bypass/RCE/priv-esc) or a less-mature program (the patch-diff method needs a target that does NOT sweep the whole class on each fix).

Related: [[2026-06-21-cycle270-gitlab-authz-asymmetry-invariants]], [[2026-06-21-HARDRULE-cash-gate-current-tier-not-historical]].

Generated 2026-07-02 13:15:04 UTC | auto-sync /15min