Skip to content

seclog: Broken object level authorization in ChaosCenter invitation and leave-project handlers #5604

Description

@naruto-lgtm

Summary

AcceptInvitation, DeclineInvitation and LeaveProject in the ChaosCenter authentication server authorize the caller with their JWT uid but then apply the mutation to a member id taken from the request body. Any project member can change another member's invitation state, including flipping the project owner to Exited, which permanently locks the owner out of their own project.

Details

File: chaoscenter/authentication/api/handlers/rest/project_handler.go
Functions: AcceptInvitation, DeclineInvitation, LeaveProject

Each handler runs validations.RbacValidator(c.MustGet("uid"), member.ProjectID, ...) against the caller's uid from the JWT context, then passes member.UserID, bound straight from the request JSON, into service.UpdateInvite. The repository's UpdateInvite builds the update with an array filter of elem.user_id == userID and _id == projectID as the only other predicate, so the write lands on whichever member the caller names rather than on the caller.

validations.MutationRbacRules admits Owner, Viewer and Executor on all three routes, so any project member (or any holder of a pending invite, for accept/decline) can reach them.

By contrast the sibling handlers that are meant to act on another member, RemoveInvitation and UpdateMemberRole, are gated at Owner and explicitly reject a UserID equal to the caller. These three are the self-service side and only ever have one valid subject.

PoC

As any accepted Viewer of project P holding a valid bearer token:

POST /leave_project with body {"projectID":"P","userID":"<owner-uid>"} and no role key.

Response is 200 {"message":"successful"}. The owner's members[] entry in the project document becomes invitation: "Exited", after which the owner's calls to /get_project/P return 401 from RbacValidator. /accept_invitation and /decline_invitation behave the same way for anyone holding a pending invite to the project.

Impact

Broken object level authorization. Any project member can alter another member's invitation state; the highest-impact case is a non-owner permanently removing the project owner's access to their own project. Once exited, the owner no longer matches CreateMatchStage or the $elemMatch in RbacValidator and cannot recover access.

Remediation

Use the authenticated uid as the subject of the UpdateInvite call in all three self-service handlers, since they only ever have one valid subject. Proposed in #5600.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions