GSuite Document External Ownership Transfer


Description

A GSuite document's ownership was transferred to an external party.

Query · python

def rule(event):
    if event.get("name") != "change_owner":
        return False

    if event.deep_get("parameters", "visibility") in (
        "shared_internally",
        "people_within_domain_with_link",
        "private",
    ):
        return False

    previous_owner = event.deep_get("parameters", "owner", default="<UNKNOWN USER>")
    new_owner = event.deep_get("parameters", "new_owner", default="<UNKNOWN USER>")

    previous_owner_domain = previous_owner.split("@")[1] if "@" in previous_owner else None
    new_owner_domain = new_owner.split("@")[1] if "@" in new_owner else None

    if previous_owner_domain is None or new_owner_domain is None:
        return False

    if previous_owner_domain != new_owner_domain:
        return True

    return False


def title(event):
    actor = event.deep_get("actor", "email", default="<UNKNOWN USER>")
    previous_owner = event.deep_get("parameters", "owner", default="<UNKNOWN USER>")
    new_owner = event.deep_get("parameters", "new_owner", default="<UNKNOWN USER>")

    return f"User [{actor}] transferred document ownership from [{previous_owner}] to [{new_owner}]"

Analyst notes

Verify that this document did not contain sensitive or private company information.

Raw source GSuite Document External Ownership Transfer · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: gsuite_doc_ownership_transfer.py
RuleID: "GSuite.DocOwnershipTransfer"
DisplayName: "GSuite Document External Ownership Transfer"
Enabled: true
LogTypes:
  - GSuite.ActivityEvent
Tags:
  - GSuite
  - Collection:Data from Information Repositories
Reports:
  MITRE ATT&CK:
    - TA0009:T1213
Severity: Low
Description: >
  A GSuite document's ownership was transferred to an external party.
Reference: https://support.google.com/drive/answer/2494892?hl=en&co=GENIE.Platform%3DDesktop&sjid=864417124752637253-EU
Runbook: >
  Verify that this document did not contain sensitive or private company information.
SummaryAttributes:
  - actor:email
Tests:
  - Name: Ownership Transferred Within Organization
    ExpectedResult: false
    Log:
      {
        "actor": {
          "email": "alice@panther.com",
          "profileId": "1234567890"
        },
        "id": {
          "applicationName": "drive",
          "customerId": "C123abcde",
          "time": "2025-08-12 18:41:56.232000000",
          "uniqueQualifier": "1234567890"
        },
        "ipAddress": "1.2.3.4",
        "kind": "admin#reports#activity",
        "name": "change_owner",
        "parameters": {
          "billable": true,
          "doc_id": "1234567890",
          "doc_title": "sensitive_document.xlsx",
          "doc_type": "msexcel",
          "new_owner": "bob@panther.com",
          "owner": "alice@panther.com",
          "primary_event": true,
          "visibility": "shared_internally"
        },
        "type": "acl_change"
      }
  - Name: Document Transferred to External User
    ExpectedResult: true
    Log:
      {
        "actor": {
          "email": "alice@panther.com",
          "profileId": "1234567890"
        },
        "id": {
          "applicationName": "drive",
          "customerId": "C123abcde",
          "time": "2025-07-11 19:50:09.324000000",
          "uniqueQualifier": "1234567890"
        },
        "kind": "admin#reports#activity",
        "name": "change_owner",
        "parameters": {
          "billable": true,
          "doc_id": "1234567890",
          "doc_title": "sensitive_document.xlsx",
          "doc_type": "msexcel",
          "new_owner": "bob@example.com",
          "owner": "alice@panther.com",
          "primary_event": true,
          "visibility": "unknown"
        },
        "type": "acl_change"
      }
  - Name: Document Transferred to Group within Organization
    ExpectedResult: false
    Log:
      {
        "actor": {
          "email": "alice@panther.com",
          "profileId": "100606748236723241722"
        },
        "id": {
          "applicationName": "drive",
          "customerId": "C123abcde",
          "time": "2025-07-07 23:50:22.743000000",
          "uniqueQualifier": "1234567890"
        },
        "ipAddress": "1.2.3.4",
        "kind": "admin#reports#activity",
        "name": "change_owner",
        "parameters": {
          "billable": true,
          "doc_id": "1234567890",
          "doc_title": "sensitive_document.xlsx",
          "doc_type": "msexcel",
          "new_owner": "Execs",
          "new_owner_is_team_drive": true,
          "new_owner_team_drive_id": "1234567890",
          "originating_app_id": "1234567890",
          "owner": "Engineering",
          "owner_is_shared_drive": true,
          "owner_is_team_drive": true,
          "owner_team_drive_id": "1234567890",
          "primary_event": true,
          "shared_drive_id": "1234567890",
          "team_drive_id": "1234567890",
          "visibility": "shared_internally"
        },
        "type": "acl_change"
      }


# ------ paired body: gsuite_doc_ownership_transfer.py ------

def rule(event):
    if event.get("name") != "change_owner":
        return False

    if event.deep_get("parameters", "visibility") in (
        "shared_internally",
        "people_within_domain_with_link",
        "private",
    ):
        return False

    previous_owner = event.deep_get("parameters", "owner", default="<UNKNOWN USER>")
    new_owner = event.deep_get("parameters", "new_owner", default="<UNKNOWN USER>")

    previous_owner_domain = previous_owner.split("@")[1] if "@" in previous_owner else None
    new_owner_domain = new_owner.split("@")[1] if "@" in new_owner else None

    if previous_owner_domain is None or new_owner_domain is None:
        return False

    if previous_owner_domain != new_owner_domain:
        return True

    return False


def title(event):
    actor = event.deep_get("actor", "email", default="<UNKNOWN USER>")
    previous_owner = event.deep_get("parameters", "owner", default="<UNKNOWN USER>")
    new_owner = event.deep_get("parameters", "new_owner", default="<UNKNOWN USER>")

    return f"User [{actor}] transferred document ownership from [{previous_owner}] to [{new_owner}]"

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.