Skip to content

fix(authz): close DeleteMembership authorization bypass#3245

Merged
matiasinsaurralde merged 2 commits into
mainfrom
fix/delete-membership-authz-bypass
Jun 26, 2026
Merged

fix(authz): close DeleteMembership authorization bypass#3245
matiasinsaurralde merged 2 commits into
mainfrom
fix/delete-membership-authz-bypass

Conversation

@matiasinsaurralde

@matiasinsaurralde matiasinsaurralde commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Closes PFM-6498

Summary

  • Add explicit ServerOperationsMap entries for OrganizationService/DeleteMembership and UpdateMembership, requiring org admin/owner membership-management policies.
  • Introduce PolicyOrganizationMembershipsDelete and PolicyOrganizationMembershipsUpdate and grant them to RoleAdmin and RoleOwner.
  • Prevents any org member (including viewers) from removing or updating other members via the unanchored regex match on the empty OrganizationService/Delete policy.

Review in cubic

Add explicit ServerOperationsMap entries so DeleteMembership no longer
inherits the empty OrganizationService/Delete policy via regex prefix match.

Signed-off-by: Matías Insaurralde <matias@chainloop.dev>
@matiasinsaurralde matiasinsaurralde requested a review from a team June 26, 2026 12:03

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread app/controlplane/pkg/authz/middleware/middleware_test.go

@migmartri migmartri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that there is no check at the service level for this?

Mirror TestViewerDeniedDeleteMembership to cover the UpdateMembership
deny path through the authz middleware.

Signed-off-by: Matías Insaurralde <matias@chainloop.dev>
@chainloop-platform

chainloop-platform Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

AI Session Analysis

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟢 89% 1 ✅ 0 100% AI / 0% Human 1 +16 / -0 1m58s

🟢 89% — 100% AI — ✅ All policies passing

Jun 26, 2026 12:40 UTC · 1m58s · $1.19 · 13.5k in / 7.5k out · claude-code 2.1.193 (claude-opus-4-8)

View session details ↗

Change Summary

  • Validates the reviewer comment against the authz fix and existing tests.
  • Adds TestViewerDeniedUpdateMembership in middleware_test.go, mirroring the delete case.
  • Runs focused go test for viewer-denied middleware coverage and commits the new test without pushing.

AI Session Overall Score

🟢 89% — Focused session with solid execution; only verification lacked explicit user confirmation.

AI Session Analysis Breakdown

🟢 97% · scope-discipline

🟢 AI changed only middleware_test.go for the requested follow-up. · High Impact

🟢 96% · alignment

No notes.

🟢 92% · solution-quality

🟢 The AI mirrored the existing delete test instead of inventing a new pattern. · High Impact

🟢 90% · context-and-planning

No notes.

🟢 88% · user-trust-signal

No notes.

🟡 79% · verification

🟢 AI ran go test and observed both viewer-denied cases pass. · High Impact

🟡 No post-commit user confirmation arrived after the test run and commit. · Low Severity


File Attribution

████████████████████ 100% AI / 0% Human

Status Attribution File Lines
modified ai app/controlplane/pkg/authz/middleware/middleware_test.go +16 / -0

Policies (4)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-74ffb9 -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-74ffb9 -
✅ Passed ai-config-no-secrets ai-coding-session-74ffb9 -
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-74ffb9 -

Powered by Chainloop and Chainloop Trace

@matiasinsaurralde

Copy link
Copy Markdown
Contributor Author

Are you sure that there is no check at the service level for this?

The service handler calls straight into the biz layer with no caller-authz check, and the only biz check (enforceManageOwners) fires solely when the target is an owner. For non-owner targets the authz middleware was the only gate, which is exactly where the bypass was. UpdateMembership was ok though:

  • DeleteMembership — the key OrganizationService/Delete exists as an empty {} entry (authz.go, main), and "…/Delete" is a prefix of "…/DeleteMembership", so the regex matched it → returned an empty policy list → the enforcement loop ran zero checks → allowed. That's the bypass.
  • UpdateMembership — there is no OrganizationService/Update key to collide with (only Create/Delete/ListMemberships exist), so nothing matched → policiesLookup returned errors.New("operation not allowed")checkPolicies returned Forbidden → denied.

There's also a demo on the ticket.

@matiasinsaurralde matiasinsaurralde requested review from a team and jiparis June 26, 2026 13:03
Comment thread app/controlplane/pkg/authz/authz.go

@migmartri migmartri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@migmartri migmartri self-requested a review June 26, 2026 13:40
@matiasinsaurralde matiasinsaurralde merged commit e7ebb3e into main Jun 26, 2026
16 checks passed
@matiasinsaurralde matiasinsaurralde deleted the fix/delete-membership-authz-bypass branch June 26, 2026 13:47
jiparis added a commit to jiparis/chainloop that referenced this pull request Jun 26, 2026
…inloop-dev#3245)"

This reverts commit e7ebb3e.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: af6e1c77-67e9-454c-8a56-5220930f328c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants