Slack Primary Owner Transferred


Description

Detects Slack Primary Owner transfers, representing the highest administrative privilege change with absolute control over workspace settings, security, billing, and data access. Primary Owners can add/remove all admins, delete entire workspaces, and transfer ownership. Unauthorized transfers indicate account compromise, insider threats, or hostile takeovers that could lead to permanent data loss or complete security control loss.

Query · python

from panther_slack_helpers import slack_alert_context


def rule(event):
    return event.get("action") == "service_owner_transferred"


def title(event):
    previous_owner = event.deep_get("actor", "user", "email", default="<UNKNOWN_PREVIOUS_OWNER>")
    new_owner = event.deep_get("entity", "user", "email", default="<UNKNOWN_NEW_OWNER>")
    workspace = event.deep_get("context", "location", "domain", default="<UNKNOWN_WORKSPACE>")
    return (
        f"Slack: Primary Owner transferred for workspace [{workspace}] "
        f"from [{previous_owner}] to [{new_owner}] - Highest privilege transfer"
    )


def alert_context(event):
    return slack_alert_context(event)

Analyst notes

  1. Query Slack audit logs for both actor.user.email and entity.user.email in the 30 days before the ownership transfer to identify suspicious authentication patterns, logins from unusual locations, or unexpected administrative actions indicating account compromise
  2. Check if entity.user.email has made any concerning administrative changes since receiving ownership such as removing administrators, disabling security controls, adding unknown users, or creating API tokens
  3. Review the context.ip_address and user agent from where the transfer was initiated to determine if it matches the previous Primary Owner's normal access patterns and geographic location
Raw source Slack Primary Owner Transferred · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: slack_service_owner_transferred.py
RuleID: "Slack.AuditLogs.ServiceOwnerTransferred"
DisplayName: "Slack Primary Owner Transferred"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Persistence
  - Account Manipulation
  - Impact
  - Account Access Removal
  - Privilege Escalation
Reports:
  MITRE ATT&CK:
    - TA0004:T1078.004
    - TA0003:T1098
    - TA0040:T1531
Severity: Critical
Description: >
  Detects Slack Primary Owner transfers, representing the highest administrative privilege change with absolute control over workspace settings, security, billing, and data access. Primary Owners can add/remove all admins, delete entire workspaces, and transfer ownership. Unauthorized transfers indicate account compromise, insider threats, or hostile takeovers that could lead to permanent data loss or complete security control loss.
Reference: https://slack.com/intl/en-gb/help/articles/204401633-Transfer-ownership-of-a-workspace-or-org
Runbook: |
  1. Query Slack audit logs for both actor.user.email and entity.user.email in the 30 days before the ownership transfer to identify suspicious authentication patterns, logins from unusual locations, or unexpected administrative actions indicating account compromise
  2. Check if entity.user.email has made any concerning administrative changes since receiving ownership such as removing administrators, disabling security controls, adding unknown users, or creating API tokens
  3. Review the context.ip_address and user agent from where the transfer was initiated to determine if it matches the previous Primary Owner's normal access patterns and geographic location
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails
Tests:
  - Name: Service Owner Transferred
    ExpectedResult: true
    Log:
      {
        "action": "service_owner_transferred",
        "actor":
          {
            "type": "user",
            "user":
              {
                "email": "user@example.com",
                "id": "A012B3CDEFG",
                "name": "username",
                "team": "T01234N56GB",
              },
          },
        "context":
          {
            "ip_address": "1.2.3.4",
            "location":
              {
                "domain": "test-workspace",
                "id": "T01234N56GB",
                "name": "test-workspace",
                "type": "workspace",
              },
            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
          },
      }
  - Name: User Logout
    ExpectedResult: false
    Log:
      {
        "action": "user_logout",
        "actor":
          {
            "type": "user",
            "user":
              {
                "email": "user@example.com",
                "id": "W012J3FEWAU",
                "name": "primary-owner",
                "team": "T01234N56GB",
              },
          },
        "context":
          {
            "ip_address": "1.2.3.4",
            "location":
              {
                "domain": "test-workspace-1",
                "id": "T01234N56GB",
                "name": "test-workspace-1",
                "type": "workspace",
              },
            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
          },
        "date_create": "2022-07-28 15:22:32",
        "entity":
          {
            "type": "user",
            "user":
              {
                "email": "user@example.com",
                "id": "W012J3FEWAU",
                "name": "primary-owner",
                "team": "T01234N56GB",
              },
          },
        "id": "72cac009-9eb3-4dde-bac6-ee49a32a1789",
      }


# ------ paired body: slack_service_owner_transferred.py ------

from panther_slack_helpers import slack_alert_context


def rule(event):
    return event.get("action") == "service_owner_transferred"


def title(event):
    previous_owner = event.deep_get("actor", "user", "email", default="<UNKNOWN_PREVIOUS_OWNER>")
    new_owner = event.deep_get("entity", "user", "email", default="<UNKNOWN_NEW_OWNER>")
    workspace = event.deep_get("context", "location", "domain", default="<UNKNOWN_WORKSPACE>")
    return (
        f"Slack: Primary Owner transferred for workspace [{workspace}] "
        f"from [{previous_owner}] to [{new_owner}] - Highest privilege transfer"
    )


def alert_context(event):
    return slack_alert_context(event)

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.