> For the complete documentation index, see [llms.txt](https://docs.forestall.io/fsprotect/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/fsprotect/edges/gcp/gws_group_owner.md).

# GWS\_GROUP\_OWNER

## Summary

|                            |                   |
| -------------------------- | ----------------- |
| **FSProtect ACL Alias**    | GWS\_GROUP\_OWNER |
| **GWS Alias**              | Group Owner       |
| **Affected Object Types**  | GWS Group         |
| **Exploitation Certainty** | Certain           |

## Description

`GWS_GROUP_OWNER` is a structural edge representing that an identity is an **owner of a Google Workspace Group**. Group owners have the highest level of control and can add or remove members, managers, and other owners; modify all group settings; and delete the group.

If the group is bound to GCP IAM roles, the owner can add a controlled identity as a member to immediately inherit those permissions at any resource scope. Beyond direct member addition, an owner can change `whoCanJoin` to `ALL_IN_DOMAIN_CAN_JOIN`, converting a restricted group into one where any org user can self-join via the Groups UI and inherit GCP IAM roles with no further admin action — a behavior Google has classified as "Won't Fix (Intended Behavior)." An owner can also enable `allowExternalMembers=true` to allow identities from outside the organization, bypassing Domain-Restricted Sharing policies, or set `whoCanLeaveGroup = NONE_CAN_LEAVE` to prevent members from removing themselves.

When any new member is added, they immediately gain access to the group's entire historical email archive. This access generates no audit event anywhere.

All group membership and settings changes are recorded only in Google Workspace audit logs. The GCP `setIamPolicy` event is never triggered by these actions.

## Identification

### gcloud CLI

```bash
# Find all GCP-bound groups across the organization
gcloud asset search-all-iam-policies \
    --scope='organizations/ORG_ID' \
    --query='memberTypes:group' \
    --format="table(resource, policy.bindings[].role, policy.bindings[].members)"
```

```bash
# List all members with OWNER role in a group
GROUP_EMAIL="target-group@example.com"
gcloud identity groups memberships list \
  --group-email=$GROUP_EMAIL \
  --format="table(preferredMemberKey.id, roles[0].name)" \
  | grep OWNER
```

### Google Admin Console

1. Open **Google Admin Console** (`admin.google.com`) → **Directory** → **Groups**.
2. Click on the target group → **Members** → filter by **Role: Owner**.
3. Check **Group settings** → **Who can join** and **Allow external members**.

## Exploitation

```bash
# As a group owner, add a controlled identity as member to inherit all GCP IAM roles
GROUP_EMAIL="privileged-group@example.com"
gcloud identity groups memberships add \
  --group-email=$GROUP_EMAIL \
  --member-email=attacker@example.com \
  --roles=MEMBER

# Wait 1-5 minutes for GCP IAM propagation
gcloud projects list
gcloud storage ls
```

## Mitigation

1. **Convert GCP-bound groups to security groups** — restricts all membership and settings changes to Super Admins only:

   ```bash
   gcloud identity groups update GROUP_EMAIL \
     --labels=cloudidentity.googleapis.com/groups.security=''
   ```
2. **Minimize group owners** — each GCP-bound group should have as few owners as necessary.
3. **Audit group ownership regularly:**

   ```bash
   gcloud identity groups memberships list \
     --group-email=SENSITIVE_GROUP_EMAIL \
     --format="table(preferredMemberKey.id, roles[0].name)" | grep OWNER
   ```
4. **Monitor group settings** on GCP-bound groups for unauthorized changes to join policy or external member settings.
5. **Enable GWS audit log export to Cloud Logging** — group settings changes are not visible in GCP without this export.

## Detection

Monitor group membership and settings changes in **Google Workspace Audit Logs**. Settings changes (join policy, external members, leave policy) appear as a separate event from membership additions and require a different filter.

### Google Admin Console

1. Open **Google Admin Console** (`admin.google.com`) → **Reporting** → **Audit and investigation** → **Groups Enterprise log events**.
2. Filter by **Event Name: Add member** or **Update member** (role changes).
3. Also filter by **Event Name: Change group settings** — specifically `whoCanJoin`, `allowExternalMembers`, `whoCanLeaveGroup`.

### Cloud Logging (GCP)

```bash
# Monitor member additions and group settings changes
gcloud logging read \
  'logName="organizations/ORG_ID/logs/cloudaudit.googleapis.com%2Factivity" AND protoPayload.serviceName="admin.googleapis.com" AND (protoPayload.methodName="google.admin.AdminService.addGroupMember" OR protoPayload.methodName="google.admin.AdminService.updateGroupSettings")' \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.request.groupKey, protoPayload.request.memberKey)"
```

## References

* <https://www.netspi.com/blog/technical-blog/cloud-pentesting/escalating-privileges-in-google-cloud-via-open-groups/>
* <https://hackersvanguard.com/the-hidden-google-groups-security-risks/>
* <https://cloud.google.com/iam/docs/groups-in-cloud-console>
* <https://developers.google.com/admin-sdk/directory/reference/rest/v1/members>
* <https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships>
* <https://cloud.google.com/security-command-center/docs/concepts-event-threat-detection-overview>
* <https://cloud.hacktricks.wiki/en/pentesting-cloud/workspace-security/gws-post-exploitation.html>
* <https://support.google.com/a/answer/167430>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestall.io/fsprotect/edges/gcp/gws_group_owner.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
