Repository navigation
Conversation
When a request carries no X-Butler-Team header, the cluster, addon,
GitOps and certificate checks short-circuited on UserSession.IsAdmin,
which is true for an admin of any team. An admin of team alpha could
therefore read, scale, delete, enable GitOps on and rotate
certificates for every other team's clusters by omitting the header.
This is the path the portal proxy uses when no team is selected.
Platform roles are now checked explicitly: platform admins and
viewers see every cluster, platform admins operate on any cluster,
and everyone else is limited to teams where they hold the needed
role. POST /teams/{name}/providers/test gets its own handler that
requires an operate role on the named team; it previously reused the
platform handler with no team check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
With no
X-Butler-Teamheader,ClusterHandler.checkClusterAccess/checkOperatePermission,AddonsHandler.checkOperatePermission,GitOpsHandler.checkOperatePermissionand the certificate checks returned early onUserSession.IsAdmin(), which means "admin of any team". An admin of team alpha could read, scale, delete, enable GitOps on, and rotate certificates for every other team's clusters by omitting the header. The portal proxy sends the header only when a team is selected, so this is its default path.POST /teams/{name}/providers/testreused the platformTestConnectionhandler with no team check. Found in the 2026-08 parity audit (D17, D8).Change
CanOperateTeam(teamRef)(orIsAdminOfTeamfor CA rotation, unchanged).ProvidersHandler.TestTeamConnectionwrapsTestConnectionwithCanOperateTeam(name); the router uses it for the team route.Verification
CGO_ENABLED=0 go build ./...,go vet ./internal/api/...cleanCGO_ENABLED=0 go test ./...passes;clusters_operate_test.goasserts an alpha team admin is confined to alpha across all five check sites and that platform viewer reads but cannot operate.X-Butler-Team, which takes the unchanged selected-team path.Depends on
None. Complements #93 (middleware tier) and #96 (management reads).
Out of scope
IsAdmin()call sites in images.go and workspaces.go (image syncs and workspace admin visibility), which need their own scoping decision.