Detection rules › Panther

Panther rules: slack

Slack Anomaly Detected

#
Severity
low
Log types
Slack.AuditLogs
Tags
Slack, Command and Control, Application Layer Protocol
Reference
api.slack.com
Source
github.com/panther-labs/panther-analysis

Passthrough for anomalies detected by Slack

MITRE ATT&CK coverage

TacticTechniques
Command & Control

Detection logic

from panther_slack_helpers import slack_alert_context

ELEVATED_ANOMALIES = {"excessive_malware_uploads", "session_fingerprint", "unexpected_admin_action"}


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


def severity(event):
    # Return "MEDIUM" for some more serious anomalies
    reasons = event.deep_get("details", "reason", default=[])
    if set(reasons) & ELEVATED_ANOMALIES:
        return "MEDIUM"
    return "DEFAULT"


def title(event):
    anomalies = {
        "asn": "An ASN was on a list of suspicious ASNs",
        "excessive_downloads": "A user downloaded an excessive amount of files",
        "excessive_file_shares": "A user shared an excessive amount of files",
        "excessive_malware_uploads": "A user uploaded an excessive amount of malware files",
        "ip_address": "An anomaly was detected in the IP address used for the user token",
        "search_volume": "An unusual volume of search activity was detected",
        "session_fingerprint": "The session cookie has an unusual timestamp or client fingerprint",
        "spoofed_user_agent": "Characteristics of the client do not match the user agent",
        "tor": "A Tor exit node was used",
        "unexpected_admin_action": "An unexpected admin action was performed",
        "unexpected_api_call_volume": "An unexpected volume of API calls was detected",
        "unexpected_client": "An anomalous Slack client was detected",
        "unexpected_credential_testing": "Unexpected credential testing activity was detected",
        "unexpected_message_deletion": "Unexpected message deletion activity was detected",
        "unexpected_scraping": "Unexpected scraping activity was detected",
        "unexpected_user_agent": "An unexpected user agent was detected",
        "user_agent": "An anomaly was detected in the user agent used for the user token",
    }

    reasons = event.deep_get("details", "reason", default=[])
    reasons_str = reasons[0] if reasons else ""
    anomaly_description = anomalies.get(reasons_str)

    actor = event.deep_get("actor", "user", "email", default="")
    actor_str = f" for {actor}" if actor else ""

    if anomaly_description:
        return f"Slack Anomaly Detected{actor_str}: {anomaly_description}"
    # if the anomaly is not in our list (for future use)
    return f"Slack Anomaly Detected{actor_str}"


def alert_context(event):
    context = slack_alert_context(event)
    context |= {"details": event.get("details", {}), "context": event.get("context", {})}
    return context

Rule specification

AnalysisType: rule
Filename: slack_passthrough_anomaly.py
RuleID: "Slack.AuditLogs.PassthroughAnomaly"
DisplayName: "Slack Anomaly Detected"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Severity: Low
Reports:
  MITRE ATT&CK:
    - TA0011:T1071
Description: Passthrough for anomalies detected by Slack
DedupPeriodMinutes: 60
Threshold: 1
Reference: 
  https://api.slack.com/admins/audit-logs-anomaly
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails
Tags:
  - Slack
  - Command and Control
  - Application Layer Protocol

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is anomaly

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • anomaly
field:"action" kind:eq value:"anomaly"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "anomaly",
  "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"
  }
}

Slack App Access Expanded

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Privilege Escalation, Account Manipulation
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack App has had its permission scopes expanded

MITRE ATT&CK coverage

TacticTechniques
Privilege Escalation

Detection logic

from panther_slack_helpers import slack_alert_context

ACCESS_EXPANDED_ACTIONS = [
    "app_scopes_expanded",
    "app_resources_added",
    "app_resources_granted",
    "bot_token_upgraded",
]


def rule(event):
    if event.get("action") not in ACCESS_EXPANDED_ACTIONS:
        return False

    # Check to confirm that app scopes actually expanded or not
    if event.get("action") == "app_scopes_expanded":
        changes = get_scope_changes(event)
        if not changes["added"]:
            return False
    return True


def title(event):
    return (
        f"Slack App [{event.deep_get('entity', 'app', 'name')}] "
        f"Access Expanded by [{event.deep_get('actor', 'user', 'name')}]"
    )


def alert_context(event):
    context = slack_alert_context(event)

    changes = get_scope_changes(event)
    context["scopes_added"] = changes["added"]
    context["scopes_removed"] = changes["removed"]

    return context


def get_scope_changes(event) -> dict[str, list[str]]:
    changes = {}

    new_scopes = event.deep_get("details", "new_scopes", default=[])
    prv_scopes = event.deep_get("details", "previous_scopes", default=[])

    changes["added"] = [x for x in new_scopes if x not in prv_scopes]
    changes["removed"] = [x for x in prv_scopes if x not in new_scopes]

    return changes


def severity(event):
    # Used to escalate to High/Critical if the app is granted admin privileges
    # May want to escalate to "Critical" depending on security posture
    if "admin" in event.deep_get("entity", "app", "scopes", default=[]):
        return "High"

    # Fallback method in case the admin scope is not directly mentioned in entity for whatever
    if "admin" in event.deep_get("details", "new_scopes", default=[]):
        return "High"

    if "admin" in event.deep_get("details", "bot_scopes", default=[]):
        return "High"

    return "Medium"

Rule specification

AnalysisType: rule
Filename: slack_app_access_expanded.py
RuleID: "Slack.AuditLogs.AppAccessExpanded"
DisplayName: "Slack App Access Expanded"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Privilege Escalation
  - Account Manipulation
Reports:
  MITRE ATT&CK:
    - TA0004:T1098
Severity: Medium
Description: Detects when a Slack App has had its permission scopes expanded
Reference: https://slack.com/intl/en-gb/help/articles/1500009181142-Manage-app-settings-and-permissions
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - action
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of app_scopes_expanded, app_resources_added, app_resources_granted, bot_token_upgraded

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • app_resources_added
  • app_resources_granted
  • app_scopes_expanded
  • bot_token_upgraded
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
nameentity.app.name

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "app_scopes_expanded",
  "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"
  },
  "date_create": "2022-07-28 16:48:14",
  "details": {
    "granular_bot_token": true,
    "is_internal_integration": false,
    "is_token_rotation_enabled_app": false,
    "new_scopes": [
      "app_mentions:read",
      "channels:join",
      "channels:read",
      "chat:write",
      "chat:write.public",
      "team:read",
      "users:read",
      "im:history",
      "groups:read",
      "reactions:write",
      "groups:history",
      "channels:history"
    ],
    "previous_scopes": [
      "app_mentions:read",
      "commands",
      "channels:join",
      "channels:read",
      "chat:write",
      "chat:write.public",
      "users:read",
      "groups:read",
      "reactions:write",
      "groups:history",
      "channels:history"
    ]
  },
  "entity": {
    "type": "workspace",
    "workspace": {
      "domain": "test-workspace-1",
      "id": "T01234N56GB",
      "name": "test-workspace-1"
    }
  },
  "id": "9d9b76ce-47bb-4838-a96a-1b5fd4d1b564"
}

Slack App Added

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Persistence, Server Software Component
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack App has been added to a workspace

MITRE ATT&CK coverage

TacticTechniques
Persistence

Detection logic

from panther_slack_helpers import slack_alert_context

APP_ADDED_ACTIONS = [
    "app_approved",
    "app_installed",
    "org_app_workspace_added",
]


def rule(event):
    return event.get("action") in APP_ADDED_ACTIONS


def title(event):
    return (
        f"Slack App [{event.deep_get('entity', 'app', 'name')}] "
        f"Added by [{event.deep_get('actor', 'user', 'name')}]"
    )


def alert_context(event):
    context = slack_alert_context(event)
    context["scopes"] = event.deep_get("entity", "app", "scopes")

    return context


def severity(event):
    # Used to escalate to High/Critical if the app is granted admin privileges
    # May want to escalate to "Critical" depending on security posture
    if "admin" in event.deep_get("entity", "app", "scopes", default=[]):
        return "High"

    # Fallback method in case the admin scope is not directly mentioned in entity for whatever
    if "admin" in event.deep_get("details", "new_scopes", default=[]):
        return "High"

    if "admin" in event.deep_get("details", "bot_scopes", default=[]):
        return "High"

    return "Medium"

Rule specification

AnalysisType: rule
Filename: slack_app_added.py
RuleID: "Slack.AuditLogs.AppAdded"
DisplayName: "Slack App Added"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Persistence
  - Server Software Component
Reports:
  MITRE ATT&CK:
    - TA0003:T1505
Severity: Medium
Description: Detects when a Slack App has been added to a workspace
Reference: https://slack.com/intl/en-gb/help/articles/202035138-Add-apps-to-your-Slack-workspace
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of app_approved, app_installed, org_app_workspace_added

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • app_approved
  • app_installed
  • org_app_workspace_added
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
nameentity.app.name

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "app_installed",
  "actor": {
    "type": "user",
    "user": {
      "email": "user@example.com",
      "id": "W012J3FEWAU",
      "name": "primary-owner",
      "team": "E012MH3HS94"
    }
  },
  "context": {
    "ip_address": "1.2.3.4",
    "location": {
      "domain": "test-panther-1",
      "id": "T01770N79GB",
      "name": "test-workspace-1",
      "type": "workspace"
    },
    "ua": "Go-http-client/2.0"
  },
  "date_create": "2021-06-08 22:16:15",
  "details": {
    "is_internal_integration": false,
    "is_token_rotation_enabled_app": false
  },
  "entity": {
    "app": {
      "id": "A049JV0H0KC",
      "is_directory_approved": true,
      "is_distributed": true,
      "name": "Notion",
      "scopes": [
        "channels:history",
        "channels:read",
        "chat:write",
        "groups:read",
        "groups:write",
        "im:read",
        "mpim:read",
        "groups:history",
        "im:history",
        "mpim:history"
      ]
    },
    "type": "app"
  }
}

Slack App Removed

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Impact, Service Stop, Defense Evasion, Indicator Removal, Clear Persistence
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack App has been removed

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context

APP_REMOVED_ACTIONS = [
    "app_restricted",
    "app_uninstalled",
    "org_app_workspace_removed",
]


def rule(event):
    return event.get("action") in APP_REMOVED_ACTIONS


def title(event):
    return (
        f"Slack App [{event.deep_get('entity', 'app', 'name')}] "
        f"Removed by [{event.deep_get('actor', 'user', 'name')}]"
    )


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_app_removed.py
RuleID: "Slack.AuditLogs.AppRemoved"
DisplayName: "Slack App Removed"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Impact
  - Service Stop
  - Defense Evasion
  - Indicator Removal
  - Clear Persistence
Reports:
  MITRE ATT&CK:
    - TA0040:T1489
    - TA0005:T1070.009
Severity: Medium
Description: Detects when a Slack App has been removed
Reference: https://slack.com/intl/en-gb/help/articles/360003125231-Remove-apps-and-customised-integrations-from-your-workspace
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of app_restricted, app_uninstalled, org_app_workspace_removed

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • app_restricted
  • app_uninstalled
  • org_app_workspace_removed
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
nameentity.app.name

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "app_restricted",
  "actor": {
    "type": "user",
    "user": {
      "email": "user@example.com",
      "id": "W012J3FEWAU",
      "name": "primary-owner",
      "team": "E012MH3HS94"
    }
  },
  "context": {
    "ip_address": "1.2.3.4",
    "location": {
      "domain": "test-panther-1",
      "id": "T01770N79GB",
      "name": "test-workspace-1",
      "type": "workspace"
    },
    "ua": "Go-http-client/2.0"
  },
  "date_create": "2021-06-08 22:16:15",
  "details": {
    "app_owner_id": "W012J3AEWAU",
    "is_internal_integration": true
  },
  "entity": {
    "app": {
      "id": "A012F34BFEF",
      "is_directory_approved": false,
      "is_distributed": false,
      "name": "app-name",
      "scopes": [
        "admin"
      ]
    },
    "type": "app"
  }
}

Slack Denial of Service via Session Invalidation

#
Severity
critical
Group by
entity.user.name
Log types
Slack.AuditLogs
Tags
Slack, Impact, Endpoint Denial of Service, Application Exhaustion Flood
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects potential DoS attacks via excessive session invalidation when administrators reset user sessions 60+ times within 24 hours. Repeated session termination prevents users from maintaining Slack access, disrupting communication and productivity. Legitimate session resets for incident response or troubleshooting typically occur 1-3 times, so reaching the 60-event threshold indicates malicious intent.

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context

DENIAL_OF_SERVICE_ACTIONS = [
    "bulk_session_reset_by_admin",
    "user_session_invalidated",
    "user_session_reset_by_admin",
]


def rule(event):
    # Only evaluate actions that could be used for a DoS
    if event.get("action") not in DENIAL_OF_SERVICE_ACTIONS:
        return False

    return True


def title(event):
    admin = event.deep_get("actor", "user", "email", default="<UNKNOWN_ADMIN>")
    target = event.deep_get("entity", "user", "name", default="<UNKNOWN_USER>")
    action = event.get("action", "<UNKNOWN_ACTION>")
    return f"Slack: Potential DoS - Admin [{admin}] performed [{action}] on user [{target}]"


def dedup(event):
    return f"Slack.AuditLogs.ApplicationDoS{event.deep_get('entity', 'user', 'name')}"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_application_dos.py
RuleID: "Slack.AuditLogs.ApplicationDoS"
DisplayName: "Slack Denial of Service via Session Invalidation"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Impact
  - Endpoint Denial of Service
  - Application Exhaustion Flood
Reports:
  MITRE ATT&CK:
    - TA0040:T1499.003
Severity: Critical
Description: >
  Detects potential DoS attacks via excessive session invalidation when administrators reset user sessions 60+ times within 24 hours. Repeated session termination prevents users from maintaining Slack access, disrupting communication and productivity. Legitimate session resets for incident response or troubleshooting typically occur 1-3 times, so reaching the 60-event threshold indicates malicious intent.
Reference: https://slack.com/intl/en-gb/help/articles/115005223763-Manage-session-duration-#pro-and-business+-subscriptions-2
Runbook: |
  1. Query Slack audit logs for all actions by actor.user.email in the 7 days around this event to identify other malicious activities such as unauthorized user removals, workspace settings changes, data exports, or app installations indicating compromised admin account
  2. Review the total number of session reset events targeting entity.user.name and the time span to calculate the frequency and determine if this represents a sustained denial of service attack
  3. Search Slack audit logs for session reset patterns targeting other users to determine if this is an isolated incident or part of a broader campaign affecting multiple users
DedupPeriodMinutes: 1440
Threshold: 60
SummaryAttributes:
  - action
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of bulk_session_reset_by_admin, user_session_invalidated, user_session_reset_by_admin
Alert cadence
alerts after 60 matches within 1d

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • bulk_session_reset_by_admin
  • user_session_invalidated
  • user_session_reset_by_admin
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
action
nameentity.user.name

Response runbook

1. Query Slack audit logs for all actions by actor.user.email in the 7 days around this event to identify other malicious activities such as unauthorized user removals, workspace settings changes, data exports, or app installations indicating compromised admin account

2. Review the total number of session reset events targeting entity.user.name and the time span to calculate the frequency and determine if this represents a sustained denial of service attack

3. Search Slack audit logs for session reset patterns targeting other users to determine if this is an isolated incident or part of a broader campaign affecting multiple users

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "user_session_reset_by_admin",
  "actor": {
    "type": "user",
    "user": {
      "email": "admin@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"
  },
  "entity": {
    "type": "user",
    "user": {
      "email": "target@example.com",
      "id": "U987654321",
      "name": "target-user",
      "team": "T01234N56GB"
    }
  }
}

Slack DLP Modified

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Impair Defenses, Disable or Modify Tools, Indicator Removal
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Data Loss Prevention (DLP) rule has been deactivated or a violation has been deleted

MITRE ATT&CK coverage

TacticTechniques
Stealth
Defense Impairment

Detection logic

from panther_slack_helpers import slack_alert_context

DLP_ACTIONS = [
    "native_dlp_rule_deactivated",
    "native_dlp_violation_deleted",
]


def rule(event):
    return event.get("action") in DLP_ACTIONS


def title(event):
    if event.get("action") == "native_dlp_rule_deactivated":
        return "Slack DLP Rule Deactivated"
    return "Slack DLP Violation Deleted"


# DLP violations can be removed by security engineers in the case of FPs
# We still want to alert on these, however those should not constitute a High severity
def severity(event):
    if event.get("action") == "native_dlp_violation_deleted":
        return "Medium"
    return "High"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_dlp_modified.py
RuleID: "Slack.AuditLogs.DLPModified"
DisplayName: "Slack DLP Modified"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Impair Defenses
  - Disable or Modify Tools
  - Indicator Removal
Reports:
  MITRE ATT&CK:
    - TA0005:T1562.001
    - TA0005:T1070
Severity: High
Description: >
  Detects when a Data Loss Prevention (DLP) rule has been deactivated or a violation has been deleted
Reference: https://slack.com/intl/en-gb/help/articles/12914005852819-Slack-Connect--Data-loss-prevention
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - action
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of native_dlp_rule_deactivated, native_dlp_violation_deleted

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • native_dlp_rule_deactivated
  • native_dlp_violation_deleted
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "native_dlp_rule_deactivated",
  "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"
  }
}

Slack EKM Config Changed

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Impair Defenses, Disable or Modify Cloud Logs
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when the logging settings for a workspace's EKM configuration has changed

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


def rule(event):
    # Only alert on the `ekm_logging_config_set` action
    return event.get("action") == "ekm_logging_config_set"


def alert_context(event):
    # TODO: Add details to the context
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_ekm_config_changed.py
RuleID: "Slack.AuditLogs.EKMConfigChanged"
DisplayName: "Slack EKM Config Changed"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Impair Defenses
  - Disable or Modify Cloud Logs
Reports:
  MITRE ATT&CK:
    - TA0005:T1562.008
Severity: High
Description: Detects when the logging settings for a workspace's EKM configuration has changed
Reference: https://slack.com/intl/en-gb/help/articles/360019110974-Slack-Enterprise-Key-Management
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is ekm_logging_config_set

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • ekm_logging_config_set
field:"action" kind:eq value:"ekm_logging_config_set"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "ekm_logging_config_set",
  "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"
  }
}

Slack EKM Slackbot Unenrolled

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Impact, Service Stop
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a workspace is longer enrolled in EKM

MITRE ATT&CK coverage

TacticTechniques
Impact

Detection logic

from panther_slack_helpers import slack_alert_context


def rule(event):
    # Only alert on the `ekm_slackbot_unenroll_notification_sent` action
    return event.get("action") == "ekm_slackbot_unenroll_notification_sent"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_ekm_slackbot_unenrolled.py
RuleID: "Slack.AuditLogs.EKMSlackbotUnenrolled"
DisplayName: "Slack EKM Slackbot Unenrolled"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Impact
  - Service Stop
Reports:
  MITRE ATT&CK:
    - TA0040:T1489
Severity: High
Description: Detects when a workspace is longer enrolled in EKM
Reference: https://slack.com/intl/en-gb/help/articles/360019110974-Slack-Enterprise-Key-Management
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is ekm_slackbot_unenroll_notification_sent

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • ekm_slackbot_unenroll_notification_sent
field:"action" kind:eq value:"ekm_slackbot_unenroll_notification_sent"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "ekm_slackbot_unenroll_notification_sent",
  "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"
  }
}

Slack Enterprise Key Management Unenrolled

#
Severity
critical
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Weaken Encryption, Compliance, Data Protection
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when Slack Enterprise Key Management (EKM) is unenrolled, removing customer-controlled encryption and reverting to Slack-managed keys. EKM allows organizations to store encryption keys externally (e.g., AWS KMS), ensuring data remains protected even from Slack infrastructure compromise. Unenrollment exposes all workspace data to decryption by Slack systems and violates compliance requirements for regulated industries.

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


def rule(event):
    # Only alert on the `ekm_unenrolled` action
    return event.get("action") == "ekm_unenrolled"


def title(event):
    actor = event.deep_get("actor", "user", "email", default="<UNKNOWN_ACTOR>")
    workspace = event.deep_get("context", "location", "domain", default="<UNKNOWN_WORKSPACE>")
    return (
        f"Slack: Workspace [{workspace}] unenrolled from Enterprise Key Management "
        f"by [{actor}] - Customer-controlled encryption disabled"
    )


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_ekm_unenrolled.py
RuleID: "Slack.AuditLogs.EKMUnenrolled"
DisplayName: "Slack Enterprise Key Management Unenrolled"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Weaken Encryption
  - Compliance
  - Data Protection
Reports:
  MITRE ATT&CK:
    - TA0005:T1600
    - TA0009:T1530
    - TA0010:T1567
Severity: Critical
Description: >
  Detects when Slack Enterprise Key Management (EKM) is unenrolled, removing customer-controlled encryption and reverting to Slack-managed keys. EKM allows organizations to store encryption keys externally (e.g., AWS KMS), ensuring data remains protected even from Slack infrastructure compromise. Unenrollment exposes all workspace data to decryption by Slack systems and violates compliance requirements for regulated industries.
Reference: https://slack.com/intl/en-gb/help/articles/360019110974-Slack-Enterprise-Key-Management
Runbook: |
  1. Query Slack audit logs for all actions by actor.user.email in the 30 days around the EKM unenrollment to identify other suspicious administrative actions such as data exports, workspace settings changes, user privilege escalations, or API token creations
  2. Check if the unenrollment occurred outside normal business hours or from an unusual context.ip_address or geographic location that doesn't match the actor's typical access patterns
  3. Search Slack audit logs for data export events, file downloads, or external sharing modifications during the period when EKM was unenrolled to assess potential data exposure while customer-controlled encryption was disabled
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is ekm_unenrolled

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • ekm_unenrolled
field:"action" kind:eq value:"ekm_unenrolled"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
domaincontext.location.domain

Response runbook

1. Query Slack audit logs for all actions by actor.user.email in the 30 days around the EKM unenrollment to identify other suspicious administrative actions such as data exports, workspace settings changes, user privilege escalations, or API token creations

2. Check if the unenrollment occurred outside normal business hours or from an unusual context.ip_address or geographic location that doesn't match the actor's typical access patterns

3. Search Slack audit logs for data export events, file downloads, or external sharing modifications during the period when EKM was unenrolled to assess potential data exposure while customer-controlled encryption was disabled

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "ekm_unenrolled",
  "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"
  }
}

Slack IDP Configuration Changed

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Persistence, Credential Access, Modify Authentication Process
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects changes to the identity provider (IdP) configuration for Slack organizations.

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context

IDP_CHANGE_ACTIONS = {
    "idp_configuration_added": "Slack IDP Configuration Added",
    "idp_configuration_deleted": "Slack IDP Configuration Deleted",
    "idp_prod_configuration_updated": "Slack IDP Configuration Updated",
}


def rule(event):
    return event.get("action") in IDP_CHANGE_ACTIONS


def title(event):
    if event.get("action") in IDP_CHANGE_ACTIONS:
        return IDP_CHANGE_ACTIONS.get(event.get("action"))
    return "Slack IDP Configuration Changed"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_idp_configuration_change.py
RuleID: "Slack.AuditLogs.IDPConfigurationChanged"
DisplayName: "Slack IDP Configuration Changed"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Persistence
  - Credential Access
  - Modify Authentication Process
Reports:
  MITRE ATT&CK:
    - TA0003:T1556
    - TA0006:T1556
Severity: High
Description: Detects changes to the identity provider (IdP) configuration for Slack organizations.
Reference: https://slack.com/intl/en-gb/help/articles/115001435788-Connect-identity-provider-groups-to-your-Enterprise-Grid-org
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - action
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of idp_configuration_added, idp_configuration_deleted, idp_prod_configuration_updated

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • idp_configuration_added
  • idp_configuration_deleted
  • idp_prod_configuration_updated
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
action

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "idp_configuration_added",
  "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"
  },
  "date_create": "2022-07-28 16:48:14"
}

Slack Information Barrier Modified

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Impair Defenses, Disable or Modify Tools
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack information barrier is deleted/updated

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Detection logic

from panther_slack_helpers import slack_alert_context

INFORMATION_BARRIER_ACTIONS = {
    "barrier_deleted": "Slack Information Barrier Deleted",
    "barrier_updated": "Slack Information Barrier Updated",
}


def rule(event):
    return event.get("action") in INFORMATION_BARRIER_ACTIONS


def title(event):
    if event.get("action") in INFORMATION_BARRIER_ACTIONS:
        return INFORMATION_BARRIER_ACTIONS.get(event.get("action"))
    return "Slack Information Barrier Modified"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_information_barrier_modified.py
RuleID: "Slack.AuditLogs.InformationBarrierModified"
DisplayName: "Slack Information Barrier Modified"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Impair Defenses
  - Disable or Modify Tools
Reports:
  MITRE ATT&CK:
    - TA0005:T1562.001
Severity: Medium
Description: Detects when a Slack information barrier is deleted/updated
Reference: https://slack.com/intl/en-gb/help/articles/360056171734-Create-information-barriers-in-Slack
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - action
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of barrier_deleted, barrier_updated

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • barrier_deleted
  • barrier_updated
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
action

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "barrier_deleted",
  "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"
  }
}

Slack Legal Hold Policy Modified

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Impair Defenses, Disable or Modify Tools
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects changes to configured legal hold policies

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Detection logic

from panther_slack_helpers import slack_alert_context

LEGAL_HOLD_POLICY_ACTIONS = {
    "legal_hold_policy_entities_deleted": "Slack Legal Hold Policy Entities Deleted",
    "legal_hold_policy_exclusion_added": "Slack Exclusions Added to Legal Hold Policy",
    "legal_hold_policy_released": "Slack Legal Hold Released",
    "legal_hold_policy_updated": "Slack Legal Hold Updated",
}


def rule(event):
    return event.get("action") in LEGAL_HOLD_POLICY_ACTIONS


def title(event):
    # Only the `legal_hold_policy_updated` event includes relevant data to deduplicate
    if event.get("action") == "legal_hold_policy_updated":
        return (
            f"Slack Legal Hold Updated "
            f"[{event.deep_get('details', 'old_legal_hold_policy', 'name')}]"
        )
    if event.get("action") in LEGAL_HOLD_POLICY_ACTIONS:
        return LEGAL_HOLD_POLICY_ACTIONS.get(event.get("action"))
    return "Slack Legal Hold Policy Modified"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_legal_hold_policy_modified.py
RuleID: "Slack.AuditLogs.LegalHoldPolicyModified"
DisplayName: "Slack Legal Hold Policy Modified"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Impair Defenses
  - Disable or Modify Tools
Reports:
  MITRE ATT&CK:
    - TA0005:T1562.001
Severity: High
Description: Detects changes to configured legal hold policies
Reference: https://slack.com/intl/en-gb/help/articles/4401830811795-Create-and-manage-legal-holds
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of legal_hold_policy_entities_deleted, legal_hold_policy_exclusion_added, legal_hold_policy_released, legal_hold_policy_updated

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • legal_hold_policy_entities_deleted
  • legal_hold_policy_exclusion_added
  • legal_hold_policy_released
  • legal_hold_policy_updated
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
namedetails.old_legal_hold_policy.name
action

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "legal_hold_policy_entities_deleted",
  "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"
  }
}

Slack MFA Settings Changed

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Modify Authentication Process, Multi-Factor Authentication
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects changes to Multi-Factor Authentication requirements

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


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


def alert_context(event):
    # TODO: Add details to context
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_mfa_settings_changed.py
RuleID: "Slack.AuditLogs.MFASettingsChanged"
DisplayName: "Slack MFA Settings Changed"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Modify Authentication Process
  - Multi-Factor Authentication
Reports:
  MITRE ATT&CK:
    - TA0005:T1556.006
Severity: High
Description: Detects changes to Multi-Factor Authentication requirements
Reference: https://slack.com/intl/en-gb/help/articles/204509068-Set-up-two-factor-authentication
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is pref.two_factor_auth_changed

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • pref.two_factor_auth_changed
field:"action" kind:eq value:"pref.two_factor_auth_changed"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "pref.two_factor_auth_changed",
  "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"
  }
}

Slack Microsoft Intune Mobile Device Management Disabled

#
Severity
critical
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Impair Defenses, Disable or Modify Tools, Mobile Security, Data Loss Prevention
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when Microsoft Intune MDM integration is disabled for Slack, removing mobile security controls and enabling data exfiltration via unmanaged devices. Intune enforces policies preventing copy/paste to unmanaged apps, requires device encryption, blocks jailbroken devices, and enables remote wipe. Disabling these controls allows unrestricted Slack access from personal or compromised devices without security restrictions.

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment
Exfiltration

Detection logic

from panther_slack_helpers import slack_alert_context


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


def title(event):
    actor = event.deep_get("actor", "user", "email", default="<UNKNOWN_ACTOR>")
    workspace = event.deep_get("context", "location", "domain", default="<UNKNOWN_WORKSPACE>")
    return (
        f"Microsoft Intune: MDM disabled for Slack workspace [{workspace}] "
        f"by [{actor}] - Mobile security controls removed"
    )


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_intune_mdm_disabled.py
RuleID: "Slack.AuditLogs.IntuneMDMDisabled"
DisplayName: "Slack Microsoft Intune Mobile Device Management Disabled"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - Impair Defenses
  - Disable or Modify Tools
  - Mobile Security
  - Data Loss Prevention
Reports:
  MITRE ATT&CK:
    - TA0005:T1562.001
    - TA0010:T1567
Severity: Critical
Description: >
  Detects when Microsoft Intune MDM integration is disabled for Slack, removing mobile security controls and enabling data exfiltration via unmanaged devices. Intune enforces policies preventing copy/paste to unmanaged apps, requires device encryption, blocks jailbroken devices, and enables remote wipe. Disabling these controls allows unrestricted Slack access from personal or compromised devices without security restrictions.
Reference: https://slack.com/intl/en-gb/help/articles/6495319642387-Set-up-Slack-for-Intune-mobile-apps
Runbook: |
  1. Query Slack audit logs for all security control modifications by actor.user.email in the 30 days around this event including EKM changes, data retention policy modifications, export permission changes, and session management settings to identify a pattern of defense evasion
  2. Search Slack audit logs for mobile app login events, file downloads, and data exports during the period when Intune MDM was disabled to detect potential data exfiltration via unmanaged mobile devices
  3. Review Microsoft Intune admin logs and Azure AD audit logs for correlated suspicious activity by the same actor such as removing devices from management or disabling other mobile security policies
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is intune_disabled

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • intune_disabled
field:"action" kind:eq value:"intune_disabled"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
domaincontext.location.domain

Response runbook

1. Query Slack audit logs for all security control modifications by actor.user.email in the 30 days around this event including EKM changes, data retention policy modifications, export permission changes, and session management settings to identify a pattern of defense evasion

2. Search Slack audit logs for mobile app login events, file downloads, and data exports during the period when Intune MDM was disabled to detect potential data exfiltration via unmanaged mobile devices

3. Review Microsoft Intune admin logs and Azure AD audit logs for correlated suspicious activity by the same actor such as removing devices from management or disabling other mobile security policies

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "intune_disabled",
  "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"
  }
}

Slack Organization Created

#
Severity
low
Log types
Slack.AuditLogs
Tags
Slack, Persistence, Create Account
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack organization is created

MITRE ATT&CK coverage

TacticTechniques
Persistence

Detection logic

from panther_slack_helpers import slack_alert_context


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


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_org_created.py
RuleID: "Slack.AuditLogs.OrgCreated"
DisplayName: "Slack Organization Created"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Persistence
  - Create Account
Reports:
  MITRE ATT&CK:
    - TA0003:T1136
Severity: Low
Description: Detects when a Slack organization is created
Reference: https://slack.com/intl/en-gb/help/articles/206845317-Create-a-Slack-workspace
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is organization_created

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • organization_created
field:"action" kind:eq value:"organization_created"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "organization_created",
  "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"
  }
}

Slack Organization Deleted

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Impact, Account Access Removal
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack organization is deleted

MITRE ATT&CK coverage

TacticTechniques
Impact

Detection logic

from panther_slack_helpers import slack_alert_context


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


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_org_deleted.py
RuleID: "Slack.AuditLogs.OrgDeleted"
DisplayName: "Slack Organization Deleted"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Impact
  - Account Access Removal
Reports:
  MITRE ATT&CK:
    - TA0040:T1531
Severity: Medium
Description: Detects when a Slack organization is deleted
Reference: https://slack.com/intl/en-gb/help/articles/204067366-Delete-a-workspace
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is organization_deleted

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • organization_deleted
field:"action" kind:eq value:"organization_deleted"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "organization_deleted",
  "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"
  }
}

Slack Potentially Malicious File Shared

#
Severity
critical
Log types
Slack.AuditLogs
Tags
Slack, Initial Access, Phishing, Spearphishing Attachment, Malware, Execution
Reference
docs.datadoghq.com
Source
github.com/panther-labs/panther-analysis

Detects when Slack's automated security scanning identifies malicious files uploaded to the workspace, indicating malware delivery or phishing attempts. Slack scans for executable malware, ransomware, phishing documents, malicious scripts, and files matching threat actor signatures. This detection indicates compromised accounts, insider threats, or successful phishing attacks where users uploaded infected files.

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


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


def title(event):
    uploader = event.deep_get("actor", "user", "email", default="<UNKNOWN_USER>")
    workspace = event.deep_get("context", "location", "domain", default="<UNKNOWN_WORKSPACE>")
    return (
        f"Slack: Malicious file detected in Slack workspace [{workspace}] "
        f"uploaded by [{uploader}] - Potential malware or phishing attack"
    )


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_potentially_malicious_file_shared.py
RuleID: "Slack.AuditLogs.PotentiallyMaliciousFileShared"
DisplayName: "Slack Potentially Malicious File Shared"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Initial Access
  - Phishing
  - Spearphishing Attachment
  - Malware
  - Execution
Reports:
  MITRE ATT&CK:
    - TA0001:T1566.001
    - TA0002:T1204.002
    - TA0040:T1486
Severity: Critical
Description: >
  Detects when Slack's automated security scanning identifies malicious files uploaded to the workspace, indicating malware delivery or phishing attempts. Slack scans for executable malware, ransomware, phishing documents, malicious scripts, and files matching threat actor signatures. This detection indicates compromised accounts, insider threats, or successful phishing attacks where users uploaded infected files.
Reference: https://docs.datadoghq.com/security/default_rules/def-003-oxv/
Runbook: |
  1. Query Slack audit logs for file_downloaded events associated with the malicious file to identify all users who downloaded it before Slack detected the threat, then coordinate with IT to isolate their endpoints and scan for malware
  2. Review actor.user.email's complete Slack audit log activity in the 7 days before the upload to identify suspicious patterns such as logins from unusual locations, sharing multiple suspicious files, or mass direct messaging indicating account compromise
  3. Search the Slack workspace for other files with similar names, file types, or uploaded from the same context.ip_address to determine if this is part of a broader malware distribution campaign
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is file_malicious_content_detected

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • file_malicious_content_detected
field:"action" kind:eq value:"file_malicious_content_detected"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
domaincontext.location.domain

Response runbook

1. Query Slack audit logs for file_downloaded events associated with the malicious file to identify all users who downloaded it before Slack detected the threat, then coordinate with IT to isolate their endpoints and scan for malware

2. Review actor.user.email's complete Slack audit log activity in the 7 days before the upload to identify suspicious patterns such as logins from unusual locations, sharing multiple suspicious files, or mass direct messaging indicating account compromise

3. Search the Slack workspace for other files with similar names, file types, or uploaded from the same context.ip_address to determine if this is part of a broader malware distribution campaign

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "file_malicious_content_detected",
  "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"
  }
}

Slack Primary Owner Transferred

#
Severity
critical
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, Persistence, Account Manipulation, Impact, Account Access Removal, Privilege Escalation
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

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.

MITRE ATT&CK coverage

Detection logic

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)

Rule specification

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

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is service_owner_transferred

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • service_owner_transferred
field:"action" kind:eq value:"service_owner_transferred"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
domaincontext.location.domain
emailentity.user.email

Response 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

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "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"
  }
}

Slack Private Channel Made Public

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Defense Evasion, File and Directory Permissions Modification, Persistence, Account Manipulation, Exfiltration, Exfiltration Over Web Service
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a channel that was previously private is made public

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


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


def alert_context(event):
    return slack_alert_context(event)


def title(event):
    channel_name = event.deep_get("entity", "channel", "name", default="<unknown_channel>")
    name = event.deep_get("actor", "user", "name", default="<unknown_user>")
    email = event.deep_get("actor", "user", "email", default="<unknown_email>")
    return f"Slack private channel {channel_name} made public by {name} <{email}>"

Rule specification

AnalysisType: rule
Filename: slack_private_channel_made_public.py
RuleID: "Slack.AuditLogs.PrivateChannelMadePublic"
DisplayName: "Slack Private Channel Made Public"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Defense Evasion
  - File and Directory Permissions Modification
  - Persistence
  - Account Manipulation
  - Exfiltration
  - Exfiltration Over Web Service
Reports:
  MITRE ATT&CK:
    - TA0005:T1222
    - TA0003:T1098
    - TA0010:T1567
Severity: High
Description: Detects when a channel that was previously private is made public
Reference: https://slack.com/intl/en-gb/help/articles/213185467-Convert-a-channel-to-private-or-public
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is private_channel_converted_to_public

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • private_channel_converted_to_public
field:"action" kind:eq value:"private_channel_converted_to_public"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
nameentity.channel.name

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "private_channel_converted_to_public",
  "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"
  }
}

Slack SSO Settings Changed

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Credential Access, Persistence, Modify Authentication Process
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects changes to Single Sign On (SSO) restrictions

MITRE ATT&CK coverage

Detection logic

from panther_slack_helpers import slack_alert_context


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


def alert_context(event):
    # TODO: Add details to context
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_sso_settings_changed.py
RuleID: "Slack.AuditLogs.SSOSettingsChanged"
DisplayName: "Slack SSO Settings Changed"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Credential Access
  - Persistence
  - Modify Authentication Process
Reports:
  MITRE ATT&CK:
    - TA0003:T1556
    - TA0006:T1556
Severity: High
Description: Detects changes to Single Sign On (SSO) restrictions
Reference: https://slack.com/intl/en-gb/help/articles/220403548-Manage-single-sign-on-settings
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is pref.sso_setting_changed

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • pref.sso_setting_changed
field:"action" kind:eq value:"pref.sso_setting_changed"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "pref.sso_setting_changed",
  "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"
  }
}

Slack User Privilege Escalation

#
Severity
high
Log types
Slack.AuditLogs
Tags
Slack, Privilege Escalation, Account Manipulation, Additional Cloud Roles
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack user gains escalated privileges

MITRE ATT&CK coverage

TacticTechniques
Privilege Escalation

Detection logic

from panther_slack_helpers import slack_alert_context

USER_PRIV_ESC_ACTIONS = {
    "owner_transferred": "Slack Owner Transferred",
    "permissions_assigned": "Slack User Assigned Permissions",
    "role_change_to_admin": "Slack User Made Admin",
    "role_change_to_owner": "Slack User Made Owner",
}


def rule(event):
    return event.get("action") in USER_PRIV_ESC_ACTIONS


def title(event):
    # This is the user taking the action.
    actor_username = event.deep_get("actor", "user", "name", default="<unknown-actor>")
    actor_email = event.deep_get("actor", "user", "email", default="<unknown-email>")
    # This is the user the action is taken on.
    entity_username = event.deep_get("entity", "user", "name", default="<unknown-actor>")
    entity_email = event.deep_get("entity", "user", "email", default="<unknown-email>")
    action = event.get("action")
    if action == "owner_transferred":
        return f"{USER_PRIV_ESC_ACTIONS[action]} from {actor_username} ({actor_email})"

    if action == "permissions_assigned":
        return f"{USER_PRIV_ESC_ACTIONS[action]} {actor_username} ({actor_email})"

    if action == "role_change_to_admin":
        return f"{USER_PRIV_ESC_ACTIONS[action]} {entity_username} ({entity_email})"

    if action == "role_change_to_owner":
        return f"{USER_PRIV_ESC_ACTIONS[action]} {entity_username} ({entity_email})"

    return f"Slack User Privilege Escalation event {action} on {entity_username} ({entity_email})"


def severity(event):
    # Downgrade severity for users assigned permissions
    if event.get("action") == "permissions_assigned":
        return "Medium"
    return "Critical"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_user_privilege_escalation.py
RuleID: "Slack.AuditLogs.UserPrivilegeEscalation"
DisplayName: "Slack User Privilege Escalation"
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Privilege Escalation
  - Account Manipulation
  - Additional Cloud Roles
Reports:
  MITRE ATT&CK:
    - TA0004:T1098.003
Severity: High
Description: Detects when a Slack user gains escalated privileges
Reference: https://slack.com/intl/en-gb/help/articles/201314026-Permissions-by-role-in-Slack
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is one of owner_transferred, permissions_assigned, role_change_to_admin, role_change_to_owner

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionin
  • owner_transferred
  • permissions_assigned
  • role_change_to_admin
  • role_change_to_owner
field:"action" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
action
nameentity.user.name
emailentity.user.email

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "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"
  },
  "entity": {
    "type": "user",
    "user": {
      "email": "user@example.com",
      "id": "W012J3FEWAU",
      "name": "primary-owner",
      "team": "T01234N56GB"
    }
  }
}

Slack User Privileges Changed to User

#
Severity
medium
Log types
Slack.AuditLogs
Tags
Slack, Impact, Account Access Removal
Reference
slack.com
Source
github.com/panther-labs/panther-analysis

Detects when a Slack account is changed to User from an elevated role.

MITRE ATT&CK coverage

TacticTechniques
Impact

Detection logic

from panther_slack_helpers import slack_alert_context


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


def title(event):
    username = event.deep_get("entity", "user", "name", default="<unknown-entity>")
    email = event.deep_get("entity", "user", "email", default="<unknown-email>")

    return f"Slack {username}'s ({email}) role changed to User"


def alert_context(event):
    return slack_alert_context(event)

Rule specification

AnalysisType: rule
Filename: slack_privilege_changed_to_user.py
RuleID: Slack.AuditLogs.UserPrivilegeChangedToUser
DisplayName: Slack User Privileges Changed to User
Enabled: true
LogTypes:
  - Slack.AuditLogs
Tags:
  - Slack
  - Impact
  - Account Access Removal
Reports:
  MITRE ATT&CK:
    - TA0040:T1531
Severity: Medium
Description: Detects when a Slack account is changed to User from an elevated role.
Reference: https://slack.com/intl/en-gb/help/articles/360018112273-Types-of-roles-in-Slack
DedupPeriodMinutes: 60
Threshold: 1
SummaryAttributes:
  - p_any_ip_addresses
  - p_any_emails

Stages and Predicates

Fires on Slack.AuditLogs events when the condition below holds.

Condition

  • action is role_change_to_user

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • role_change_to_user
field:"action" kind:eq value:"role_change_to_user"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
actor-nameactor.user.name
actor-emailactor.user.email
actor-ipcontext.ip_address
user-agentcontext.ua
nameentity.user.name
emailentity.user.email

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "role_change_to_user",
  "actor": {
    "type": "user",
    "user": {
      "email": "slack-enterprise-example@example.io",
      "id": "W015MH5MPGE",
      "name": "primary-owner",
      "team": "T017E0M3CQ4"
    }
  },
  "context": {
    "ip_address": "12.12.12.12",
    "location": {
      "domain": "example-workspace-domain",
      "id": "T017E0M3CQ4",
      "name": "example-workspace",
      "type": "workspace"
    },
    "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
  },
  "date_create": "2023-02-24 18:34:18",
  "entity": {
    "type": "user",
    "user": {
      "email": "example-account@example.com",
      "id": "U04R70MM40K",
      "name": "Example Account",
      "team": "T017E0M3CQ4"
    }
  },
  "id": "4c248a02-119c-4f76-ba5d-a96767d45be8"
}