← Back to all reports

Group Admin Membership Injection Exposes Private Investigations

Reported Jun 3, 2026
Severity High
Platform Web / API
Vulnerability Class Broken Access Control / IDOR (CWE-639)
Target Type Investigative Search Platform
Impact A low-privilege group admin injects arbitrary users to read and tamper with private investigations

The Risk

A junior team member with permission to manage one small group could quietly pull any other person in the company, including a senior administrator, into that group and then read, edit, and secretly keep access to their private case files. It took a single logged-in session and a few lines pasted into a browser, with nothing the victim had to click and no inside knowledge needed. On a platform that stores sensitive investigation records, this meant one ordinary user could end up reading and altering everyone else's confidential casework across the whole organization.

The Vulnerability

The platform organizes users into groups. A regular user can be made a "Group Admin" of a single group, which is meant to let them manage only the members of that one group. Cases (called investigations) are private to their owner, and the only legitimate way one user sees another user's case is the platform's Investigation Sharing feature.

The root flaw was in the group membership endpoint:

  • PATCH /api/groups/{id} performed no management-scope check on the users being added

Because of this, a Group Admin could inject any user in the same organization into the group they controlled, including an organization administrator who belonged to a completely different group. The endpoint returned HTTP 200 regardless. The attacker's group had Investigation Sharing enabled, so once a victim was a member, the victim's private cases became visible to the attacker.

The Attack

The entire chain ran in a browser as a low-privilege member, with no administrator login at any point. Each step below was a single request issued from the attacker's authenticated session.

Selecting a Victim

The security model explicitly permits a member to list users in their own organization. That listing returned every user's id, email, and role, including the organization administrator:

GET /api/users  ->  full org user listing (id, email, role)

Confirming the Boundary

Before the attack, the member could not enumerate the victim's cases. Listing another user's investigations was rejected:

GET /api/cases?user_id={victim}  ->  403 Forbidden

The Injection

The attacker injected the organization administrator into the attacker-controlled group. This is the core authorization flaw, with no scope check on the target user:

PATCH /api/groups/{group_id}
{"add_members":[{"user_id":"{victim}","user_role":"user"}]}
->  200 OK

With the victim now a member of a group that has sharing enabled, the previously blocked enumeration flipped open:

GET /api/cases?user_id={victim}  ->  200 OK + all of the victim's case ids

No case id was needed in advance. The attacker could discover the victim's id from the permitted user listing, inject them, and then enumerate all of their cases.

Persistence Beyond the Injection

The injection was only the bootstrap. While the victim was a member, the attacker wrote a sharing policy onto the victim's case naming the attacker's own group as the principal, with read and update operations:

PATCH /api/cases/{id}
{"policies":[{"principal_id":"{attacker_group}","operation":"read"},
            {"principal_id":"{attacker_group}","operation":"update"}]}

The attacker then removed the victim from the group, restoring it to its original single-member state so the obvious indicator was gone. With no group membership at all, the attacker still read and still tampered with the victim's case, because the case was now shared to the attacker's own group and the attacker remained in that group. Removing the planted policy revoked the access, confirming that the policy, not the membership, was the surviving grant. The persistence was per-case: one policy was planted on each case the attacker wanted to keep, during the injection window. This forged the Investigation Sharing relationship that the platform defines as the only legitimate cross-user path, self-granted without the owner's consent.

The Impact

The chain was validated end to end against the test environment's seed dataset. After injection, the attacker read the organization administrator's private case cross-user (HTTP 200), then used the ids inside it to read the administrator's actual search results: match scores, source references, and result record URLs. On an investigative search platform, this is organization-wide disclosure of other analysts' confidential case files.

The same membership injection granted write access. Once a victim was injected, the attacker could alter the victim's case comments and sharing policies. A marker written by the attacker was observed from the victim's own session, confirming durable cross-user tampering rather than a response echo.

This violated two of the program's stated high-impact conditions: write access by a group admin to an organization admin, and any access by a regular user to objects owned by another user except when explicitly invited through Investigation Sharing. The attacker forged exactly that sharing for arbitrary, non-consenting victims.

Two boundaries did hold. Hard delete and archive were gated behind an owner-only flow, so destruction of a victim's case was not achievable; the proven write impact was content and sharing-policy tampering. The attack was also intra-organization only. Injecting a user from a different organization was rejected, so the tenant boundary held and impact was confined to the attacker's own organization.

Responsible Testing

All testing used the program's sandboxed seed dataset against attacker and victim accounts provisioned for the test. No real individual's personal records were processed, and every change was reverted to a clean state after validation.

Remediation

  • The group membership endpoint must verify the Group Admin is authorized to manage each user being added, and reject a non-organization-admin Group Admin adding organization admins or users from other groups.
  • Investigation sharing-policy writes should require the policy author to own the investigation, preventing self-granted persistence.
  • Membership mutations should be logged and should notify the affected user, so silent injection is detectable.
  • Audit existing sharing policies for entries whose principal is a group the case owner never shared with.