Detection rules › Panther
Panther rules: google
Google Workspace Admin Custom Role
#A Google Workspace administrator created a new custom administrator role.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Google Workspace | CREATE_ROLE: Create Role |
Detection logic
def rule(event):
# Return True to match the log event and trigger an alert.
# Create Alert if there is a custom role created under delegated admin settings
return (
event.get("type", "") == "DELEGATED_ADMIN_SETTINGS"
and event.get("name", "") == "CREATE_ROLE"
)
def title(event):
# (Optional) Return a string which will be shown as the alert title.
# If no 'dedup' function is defined, the return value of this method
# will act as deduplication string.
return (
f"Google Workspace Administrator "
f"[{event.get('actor',{}).get('email','NO_EMAIL_FOUND')}] "
f"created a new admin role "
f"[{event.get('parameters',{}).get('ROLE_NAME','NO_ROLE_NAME_FOUND')}]."
)
Rule specification
AnalysisType: rule
Description: A Google Workspace administrator created a new custom administrator role.
DisplayName: "Google Workspace Admin Custom Role"
Enabled: true
Filename: google_workspace_admin_custom_role.py
Runbook: Please review this activity with the administrator and ensure this behavior was authorized.
Reference: https://support.google.com/a/answer/2406043?hl=en#:~:text=under%20the%20limit.-,Create%20a%20custom%20role,-Before%20you%20begin
Severity: Medium
Tags:
- admin
- administrator
- google workspace
- role
DedupPeriodMinutes: 60
LogTypes:
- GSuite.ActivityEvent
RuleID: "Google.Workspace.Admin.Custom.Role"
SummaryAttributes:
- name
- type
Threshold: 1
Stages and Predicates
Fires on GSuite.ActivityEvent events when all of the conditions below hold.
Condition
typeisDELEGATED_ADMIN_SETTINGSnameisCREATE_ROLE
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
name | eq |
| field:"name" kind:eq value:"CREATE_ROLE" |
type | eq |
| field:"type" kind:eq value:"DELEGATED_ADMIN_SETTINGS" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
ROLE_NAME | parameters.ROLE_NAME |
Response runbook
Please review this activity with the administrator and ensure this behavior was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"callerType": "USER",
"email": "example@example.io",
"profileId": "123456"
},
"id": {
"applicationName": "admin",
"customerId": "D12345",
"time": "2022-12-11 02:57:48.693000000",
"uniqueQualifier": "-12456"
},
"ipAddress": "12.12.12.12",
"kind": "admin#reports#activity",
"name": "CREATE_ROLE",
"parameters": {
"ROLE_ID": "567890",
"ROLE_NAME": "CustomAdminRoleName"
},
"type": "DELEGATED_ADMIN_SETTINGS"
}
Google Workspace Advanced Protection Program
#Your organization's Google Workspace Advanced Protection Program settings were modified.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Google Workspace | CREATE_APPLICATION_SETTING: Application Setting Creation |
Detection logic
def rule(event):
# Return True to match the log event and trigger an alert.
setting_name = (
event.deep_get("parameters", "SETTING_NAME", default="NO_SETTING_NAME")
.split("-")[0]
.strip()
)
setting_alert_flag = "Advanced Protection Program Settings"
return event.get("name") == "CREATE_APPLICATION_SETTING" and setting_name == setting_alert_flag
def title(event):
# If no 'dedup' function is defined, the return value of this
# method will act as deduplication string.
setting = event.deep_get("parameters", "SETTING_NAME", default="NO_SETTING_NAME")
setting_name = setting.split("-")[-1].strip()
return (
f"Google Workspace Advanced Protection Program settings have been updated to "
f"[{setting_name}] by Google Workspace User "
f"[{event.deep_get('actor', 'email', default='<NO_EMAIL_FOUND>')}]."
)
Rule specification
AnalysisType: rule
Description: Your organization's Google Workspace Advanced Protection Program settings were modified.
DisplayName: "Google Workspace Advanced Protection Program"
Enabled: true
Filename: google_workspace_advanced_protection_program.py
Runbook: Confirm the changes made were authorized for your organization.
Reference: https://support.google.com/a/answer/9378686?hl=en
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- GSuite.ActivityEvent
RuleID: "Google.Workspace.Advanced.Protection.Program"
Threshold: 1
Stages and Predicates
Fires on GSuite.ActivityEvent events when the condition below holds.
Condition
nameisCREATE_APPLICATION_SETTING
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.
| Field | Kind | Values | Search |
|---|---|---|---|
name | eq |
| field:"name" kind:eq value:"CREATE_APPLICATION_SETTING" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
Response runbook
Confirm the changes made were authorized for your organization.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"callerType": "USER",
"email": "example@example.io",
"profileId": "12345"
},
"id": {
"applicationName": "admin",
"customerId": "D12345",
"time": "2022-12-11 01:35:29.906000000",
"uniqueQualifier": "-12345"
},
"ipAddress": "12.12.12.12",
"kind": "admin#reports#activity",
"name": "CREATE_APPLICATION_SETTING",
"parameters": {
"APPLICATION_EDITION": "standard",
"APPLICATION_NAME": "Security",
"NEW_VALUE": "ALLOWED_WITH_REMOTE_ACCESS",
"ORG_UNIT_NAME": "Example IO",
"SETTING_NAME": "Advanced Protection Program Settings - Allow security codes"
},
"type": "APPLICATION_SETTINGS"
}
Google Workspace Apps Marketplace Allowlist
#Google Workspace Marketplace application allowlist settings were modified.
Detection logic
def rule(event):
# Return True to match the log event and trigger an alert.
setting_name = event.deep_get("parameters", "SETTING_NAME", default="<NO_SETTING_NAME>")
old_val = event.deep_get("parameters", "OLD_VALUE", default="<NO_OLD_VALUE_FOUND>")
new_val = event.deep_get("parameters", "NEW_VALUE", default="<NO_NEW_VALUE_FOUND>")
return setting_name == "ENABLE_G_SUITE_MARKETPLACE" and old_val != new_val
def title(event):
# (Optional) Return a string which will be shown as the alert title.
# If no 'dedup' function is defined, the return value of this
# method will act as deduplication string.
value_dict = {
"DEFAULT": "DEFAULT",
"1": "Don't allow users to install and run apps from the Marketplace",
"2": "Allow users to install and run any app from the Marketplace",
"3": "Allow users to install and run only selected apps from the Marketplace",
}
old_val = event.deep_get("parameters", "OLD_VALUE", default="<NO_OLD_VALUE_FOUND>")
new_val = event.deep_get("parameters", "NEW_VALUE", default="<NO_NEW_VALUE_FOUND>")
actor = event.deep_get("actor", "email", default="<NO_EMAIL_FOUND>")
return (
f"Google Workspace User [{actor}] "
f"made an application allowlist setting change from [{value_dict.get(str(old_val))}] "
f"to [{value_dict.get(str(new_val))}]"
)
Rule specification
AnalysisType: rule
Description: Google Workspace Marketplace application allowlist settings were modified.
DisplayName: "Google Workspace Apps Marketplace Allowlist"
Enabled: true
Filename: google_workspace_apps_marketplace_allowlist.py
Runbook: Confirm with the acting user that this change was authorized.
Reference: https://support.google.com/a/answer/6089179?hl=en
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- GSuite.ActivityEvent
RuleID: "Google.Workspace.Apps.Marketplace.Allowlist"
Threshold: 1
Stages and Predicates
Fires on GSuite.ActivityEvent events when all of the conditions below hold.
Condition
parameters.SETTING_NAMEisENABLE_G_SUITE_MARKETPLACEparameters.OLD_VALUEdiffers from fieldparameters.NEW_VALUE
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
parameters.OLD_VALUE | cross_field_compare |
| field:"parameters.OLD_VALUE" kind:cross_field_compare value:"parameters.NEW_VALUE" |
parameters.SETTING_NAME | eq |
| field:"parameters.SETTING_NAME" kind:eq value:"ENABLE_G_SUITE_MARKETPLACE" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
OLD_VALUE | parameters.OLD_VALUE |
NEW_VALUE | parameters.NEW_VALUE |
Response runbook
Confirm with the acting user that this change was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"callerType": "USER",
"email": "example@example.io",
"profileId": "12345"
},
"id": {
"applicationName": "admin",
"customerId": "D12345",
"time": "2022-12-10 23:38:45.125000000",
"uniqueQualifier": "-12345"
},
"ipAddress": "12.12.12.12",
"kind": "admin#reports#activity",
"name": "CHANGE_EMAIL_SETTING",
"parameters": {
"NEW_VALUE": "3",
"OLD_VALUE": "2",
"ORG_UNIT_NAME": "EXAMPLE IO",
"SETTING_NAME": "ENABLE_G_SUITE_MARKETPLACE"
},
"type": "EMAIL_SETTINGS"
}
Google Workspace Apps Marketplace New Domain Application
#A Google Workspace User configured a new domain application from the Google Workspace Apps Marketplace.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Google Workspace | ADD_APPLICATION: Add Application |
Detection logic
def rule(event):
# Return True to match the log event and trigger an alert.
return (
event.get("name") == "ADD_APPLICATION"
and event.get("parameters", {}).get("APPLICATION_ENABLED", "<NO_APPLICATION_FOUND>")
== "true"
)
def title(event):
# (Optional) Return a string which will be shown as the alert title.
# If no 'dedup' function is defined, the return value of this method
# will act as deduplication string.
return (
f"Google Workspace User [{event.get('actor',{}).get('email','<NO_EMAIL_PROVIDED>')}] "
f"enabled a new Google Workspace Marketplace application "
f"[{event.get('parameters',{}).get('APPLICATION_NAME','<NO_APPLICATION_NAME_FOUND>')}]"
)
Rule specification
AnalysisType: rule
Description: A Google Workspace User configured a new domain application from the Google Workspace Apps Marketplace.
DisplayName: "Google Workspace Apps Marketplace New Domain Application"
Enabled: true
Filename: google_workspace_apps_marketplace_new_domain_application.py
Runbook: Confirm this was the intended behavior.
Reference: https://developers.google.com/workspace/marketplace/overview
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- GSuite.ActivityEvent
RuleID: "Google.Workspace.Apps.Marketplace.New.Domain.Application"
Threshold: 1
Stages and Predicates
Fires on GSuite.ActivityEvent events when all of the conditions below hold.
Condition
nameisADD_APPLICATIONparameters.APPLICATION_ENABLEDistrue
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
name | eq |
| field:"name" kind:eq value:"ADD_APPLICATION" |
parameters.APPLICATION_ENABLED | eq |
| field:"parameters.APPLICATION_ENABLED" kind:eq value:"true" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
APPLICATION_NAME | parameters.APPLICATION_NAME |
Response runbook
Confirm this was the intended behavior.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"callerType": "USER",
"email": "example@example.io",
"profileId": "12345"
},
"id": {
"applicationName": "admin",
"customerId": "D12345",
"time": "2022-12-10 23:05:39.508000000",
"uniqueQualifier": "-12345"
},
"kind": "admin#reports#activity",
"name": "ADD_APPLICATION",
"parameters": {
"APPLICATION_ENABLED": "true",
"APPLICATION_NAME": "DocuSign eSignature for Google",
"APP_ID": "469176070494"
},
"type": "DOMAIN_SETTINGS"
}
Google Workspace Apps New Mobile App Installed
#A new mobile application was added to your organization's mobile apps whitelist in Google Workspace Apps.
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Google Workspace | ADD_MOBILE_APPLICATION_TO_WHITELIST: Mobile application whitelisted |
Detection logic
def rule(event):
# Return True to match the log event and trigger an alert.
return event.get("name", "") == "ADD_MOBILE_APPLICATION_TO_WHITELIST"
def title(event):
# If no 'dedup' function is defined, the return value of
# this method will act as deduplication string.
mobile_app_pkg_id = event.get("parameters", {}).get(
"MOBILE_APP_PACKAGE_ID", "<NO_MOBILE_APP_PACKAGE_ID_FOUND>"
)
return (
f"Google Workspace User [{event.get('actor',{}).get('email','<NO_EMAIL_FOUND>')}] "
f"added application "
f"[{mobile_app_pkg_id}] "
f"to your org's mobile application allowlist for "
f"[{event.get('parameters',{}).get('DEVICE_TYPE','<NO_DEVICE_TYPE_FOUND>')}]."
)
Rule specification
AnalysisType: rule
Description: A new mobile application was added to your organization's mobile apps whitelist in Google Workspace Apps.
DisplayName: "Google Workspace Apps New Mobile App Installed"
Enabled: true
Filename: google_workspace_apps_new_mobile_app_installed.py
Runbook: https://admin.google.com/ac/apps/unified
Reference: https://support.google.com/a/answer/6089179?hl=en
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- GSuite.ActivityEvent
RuleID: "Google.Workspace.Apps.New.Mobile.App.Installed"
Threshold: 1
Stages and Predicates
Fires on GSuite.ActivityEvent events when the condition below holds.
Condition
nameisADD_MOBILE_APPLICATION_TO_WHITELIST
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
name | eq |
| field:"name" kind:eq value:"ADD_MOBILE_APPLICATION_TO_WHITELIST" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
MOBILE_APP_PACKAGE_ID | parameters.MOBILE_APP_PACKAGE_ID |
DEVICE_TYPE | parameters.DEVICE_TYPE |
Response runbook
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"callerType": "USER",
"email": "example@example.io",
"profileId": "12345"
},
"id": {
"applicationName": "admin",
"customerId": "D12345",
"time": "2022-12-10 22:55:38.478000000",
"uniqueQualifier": "12345"
},
"ipAddress": "12.12.12.12",
"kind": "admin#reports#activity",
"name": "ADD_MOBILE_APPLICATION_TO_WHITELIST",
"parameters": {
"DEVICE_TYPE": "Android",
"DISTRIBUTION_ENTITY_NAME": "/",
"DISTRIBUTION_ENTITY_TYPE": "ORG_UNIT",
"MOBILE_APP_PACKAGE_ID": "com.google.android.calculator"
},
"type": "MOBILE_SETTINGS"
}
Google Workspace Many Docs Downloaded
#Checks whether a user has downloaded a large number of documents from Google Drive within a 5-minute period.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Exfiltration |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Google Workspace | download: Download |
Rules detecting the same action
These rules filter on the same operation.
Detection logic
from panther_core import PantherEvent
def rule(event: PantherEvent) -> bool:
if event.deep_get("id", "applicationName") != "drive":
return False
return event.get("name") == "download"
def alert_context(event: PantherEvent) -> dict:
return {
"actor": event.deep_get("actor", "email", default="<UNKNOWN ACTOR>"),
"document_name": event.deep_get("parameters", "doc_title", default="<UNKNOWN DOCUMENT>"),
}
Rule specification
AnalysisType: rule
Filename: google_workspace_many_docs_downloaded.py
RuleID: "Google.Workspace.ManyDocsDownloaded"
DisplayName: Google Workspace Many Docs Downloaded
Enabled: true
LogTypes:
- GSuite.ActivityEvent
Severity: Info
CreateAlert: false
Reports:
MITRE ATT&CK:
- TA0010:T1567
Description: >
Checks whether a user has downloaded a large number of documents from Google Drive
within a 5-minute period.
DedupPeriodMinutes: 5
Threshold: 20
Reference: >
https://support.google.com/drive/answer/2423534?hl=en&co=GENIE.Platform%3DDesktop
SummaryAttributes:
- p_any_usernames
- parameters:doc_title
Tags:
- GSuite ActivityEvent
Status: Experimental
Stages and Predicates
Fires on GSuite.ActivityEvent events when all of the conditions below hold.
Condition
id.applicationNameisdrivenameisdownload
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
id.applicationName | eq |
| field:"id.applicationName" kind:eq value:"drive" |
name | eq |
| field:"name" kind:eq value:"download" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
actor | actor.email |
document_name | parameters.doc_title |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"email": "john@justice.org",
"profileId": "112233445566778899001"
},
"id": {
"applicationName": "drive",
"customerId": "CUSTID",
"time": "2025-03-21 21:29:49.364000000",
"uniqueQualifier": "-1234567891234567890"
},
"ipAddress": "1.1.1.1",
"kind": "admin#reports#activity",
"name": "download",
"parameters": {
"billable": true,
"doc_id": "123456789aBcDeFgHiJkLmNoPqRsTuVwXyZ0-a1B2c3D",
"doc_title": "My Sensitive Document",
"doc_type": "spreadsheet",
"owner": "HR",
"owner_is_shared_drive": true,
"owner_is_team_drive": true,
"owner_team_drive_id": "123456789aB_a1B2c3D",
"primary_event": true,
"shared_drive_id": "123456789aB_a1B2c3D",
"team_drive_id": "123456789aB_a1B2c3D",
"visibility": "shared_internally"
},
"type": "access"
}