Detection rules › Panther
Panther rules: auth0
Auth0 Attack Protection Monitoring Disabled
#An attack protection monitoring configuration was changed.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_type = event.deep_get("data", "type", default="<NO_DATA_TYPE_FOUND>")
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
response_body_enabled = event.deep_get(
"data", "details", "response", "body", "enabled", default="<NO_ENABLED_INFO_FOUND>"
)
response_body_shields = event.deep_get(
"data", "details", "response", "body", "shields", default="<NO_SHIELD_INFO_FOUND>"
)
response_status_code = event.deep_get(
"data", "details", "response", "statusCode", default="<NO_RESPONSE_CODE_FOUND>"
)
return all(
[
data_type == "sapi",
(
(
"Suspicious IP Throttling" in data_description
and request_path == "/v2/attack-protection/suspicious-ip-throttling"
)
or (
"Brute-force" in data_description
and request_path == "/v2/attack-protection/brute-force-protection"
)
or (
"Breached Password Detection" in data_description
and request_path == "/v2/attack-protection/breached-password-detection"
)
),
(
(response_body_enabled is False or response_body_enabled == "disabled")
or (
(response_body_enabled is True or response_body_enabled == "enabled")
and response_body_shields != "block"
)
),
response_status_code == 200,
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
response_body_enabled = event.deep_get(
"data", "details", "response", "body", "enabled", default="<NO_ENABLED_INFO_FOUND>"
)
response_body_shields = event.deep_get(
"data", "details", "response", "body", "shields", default="<NO_SHIELD_INFO_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] updated shields to [{response_body_shields}]"
f"or set attack protection monitoring to [{response_body_enabled}]"
f"with message [{data_description}] in"
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An attack protection monitoring configuration was changed.
DisplayName: "Auth0 Attack Protection Monitoring Disabled"
Enabled: true
Filename: auth0_attack_protection_disabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://github.com/auth0/auth0-customer-detections/tree/main/detections
Severity: High
Reports:
MITRE ATT&CK:
- TA0005:T1562
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.AttackProtection.Disabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.typeissapiany of:
all of:
data.descriptioncontainsSuspicious IP Throttlingdata.details.request.pathis/v2/attack-protection/suspicious-ip-throttling
all of:
data.descriptioncontainsBrute-forcedata.details.request.pathis/v2/attack-protection/brute-force-protection
all of:
data.descriptioncontainsBreached Password Detectiondata.details.request.pathis/v2/attack-protection/breached-password-detection
any of:
data.details.response.body.enabledisfalsedata.details.response.body.enabledisdisabledall of:
any of:
data.details.response.body.enabledistruedata.details.response.body.enabledisenabled
data.details.response.body.shieldsis notblock
data.details.response.statusCodeis200data.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | contains |
| field:"data.description" kind:contains |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq |
data.details.response.body.enabled | eq |
| field:"data.details.response.body.enabled" kind:eq |
data.details.response.body.shields | ne |
| field:"data.details.response.body.shields" kind:ne value:"block" |
data.details.response.statusCode | eq |
| field:"data.details.response.statusCode" kind:eq value:"200" |
data.type | eq |
| field:"data.type" kind:eq value:"sapi" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
shields | data.details.response.body.shields |
enabled | data.details.response.body.enabled |
description | data.description |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-03 14:09:32.149000000",
"description": "Update Suspicious IP Throttling settings",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000ecaf1bfbadb06900d22049"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"enabled": true
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/v2/attack-protection/suspicious-ip-throttling",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"enabled": false
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "00000000004a745ce33b57be383c543e",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Bot Detection Policy Disabled
#A bot detection policy was disabled.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_type = event.deep_get("data", "type", default="<NO_DATA_TYPE_FOUND>")
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
bot_p_policy = event.deep_get(
"data",
"details",
"response",
"body",
"passwordless_policy",
default="<NO_PASSWORDLESS_POLICY_FOUND>",
)
bot_reset_policy = event.deep_get(
"data",
"details",
"response",
"body",
"password_reset_policy",
default="<NO_PASSWORD_RESET_POLICY_FOUND>",
)
bot_policy = event.deep_get(
"data", "details", "response", "body", "policy", default="<NO_BOT_POLICY_FOUND>"
)
response_status_code = event.deep_get(
"data", "details", "response", "statusCode", default="<NO_RESPONSE_CODE_FOUND>"
)
return all(
[
data_type == "sapi",
(
data_description == "Create or update the anomaly detection captcha"
and (bot_p_policy == "off" or bot_reset_policy == "off" or bot_policy == "off")
),
response_status_code == 200,
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] disabled bot detection in "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: A bot detection policy was disabled.
DisplayName: "Auth0 Bot Detection Policy Disabled"
Enabled: true
Filename: auth0_bot_detection_disabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://github.com/auth0/auth0-customer-detections/tree/main/detections
Severity: High
Reports:
MITRE ATT&CK:
- TA0005:T1562
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.BotDetection.Disabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.typeissapidata.descriptionisCreate or update the anomaly detection captchaany of:
data.details.response.body.passwordless_policyisoffdata.details.response.body.password_reset_policyisoffdata.details.response.body.policyisoff
data.details.response.statusCodeis200data.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-03 14:09:32.149000000",
"description": "Create or update the anomaly detection captcha",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000ecaf1bfbadb06900d22049"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"enabled": true
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/v2/attack-protection/bot-detection",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"password_reset_policy": false,
"passwordless_policy": false,
"policy": false
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "00000000004a745ce33b57be383c543e",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Brute Force
#Scheduled rule for brute force detection for Auth0 login or signup which looks for incidents of more than 10 incidents in one hour
Detection logic
from panther_core import PantherEvent
def rule(event: PantherEvent) -> bool: # pylint: disable=unused-argument
return True
def title(event: PantherEvent) -> str:
total_incidents = event.get("total_incidents", 5)
return f"Auth0 Brute Force detected: {total_incidents} attempts in the past hour"
Rule specification
AnalysisType: scheduled_rule
Filename: auth0_login_brute_force.py
DisplayName: "Auth0 Brute Force"
Enabled: true
Severity: Medium
Description: Scheduled rule for brute force detection for Auth0 login or signup which looks for incidents of more than 10 incidents in one hour
DedupPeriodMinutes: 60
Threshold: 1
Reference: https://auth0.com/docs/deploy-monitor/logs/log-event-type-codes
InlineFilters:
- All: []
ScheduledQueries:
- Auth0 Brute Force Detection
RuleID: "Auth0.Brute.Force"
Stages and Predicates
Rule logic
This rule alerts on rows returned by its scheduled query Auth0 Brute Force Detection; its Python module (Detection logic above) shapes the alert rather than filtering.
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field |
|---|
total_incidents |
Auth0 Brute Force Detection
#Rule specification
AnalysisType: scheduled_query
QueryName: Auth0 Brute Force Detection
Enabled: false
# run every hour and look for >= 5 incidents in the last hour
SnowflakeQuery: |
SELECT
data, COUNT(*) OVER () AS total_incidents
FROM
panther_logs.public.auth0_events
WHERE
data:type IN ('limit_mu', 'limit_sul', 'limit_wc')
AND p_occurs_since('1 hour')
QUALIFY COUNT(*) OVER () > 4
DatabricksQuery: |
SELECT * FROM (
SELECT
data, COUNT(*) OVER () AS total_incidents
FROM
panther_logs.auth0_events
WHERE
data:type IN ('limit_mu', 'limit_sul', 'limit_wc')
AND p_occurs_since('1 hour')
) WHERE total_incidents > 4
Schedule:
CronExpression: '0 * * * *'
TimeoutMinutes: 1
Stages and Predicates
Stage 1: source
Stage 2: filter
data:typeis one oflimit_mu,limit_sul,limit_wc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data:type | in |
| field:"data:type" kind:in |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
data | |
total_incidents | COUNT ( * ) OVER ( ) |
Auth0 CIC Credential Stuffing
#Okta has determined that the cross-origin authentication feature in Customer Identity Cloud (CIC) is prone to being targeted by threat actors orchestrating credential-stuffing attacks. Okta has observed suspicious activity that started on April 15, 2024. Review tenant logs for unexpected fcoa and scoa events.
Detection logic
from panther_auth0_helpers import auth0_alert_context
SUSPICIOUS_EVENT_TYPES = (
"scoa",
"fcoa",
)
def rule(event):
return event.deep_get("data", "type") in SUSPICIOUS_EVENT_TYPES
def title(event):
event_type = event.deep_get("data", "type")
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] had a suspicious [{event_type}] event in "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
LogTypes:
- Auth0.Events
RuleID: "Auth0.CIC.Credential.Stuffing"
Filename: auth0_cic_credential_stuffing.py
DisplayName: "Auth0 CIC Credential Stuffing"
Description: Okta has determined that the cross-origin authentication feature in Customer Identity Cloud (CIC) is prone to being targeted by threat actors orchestrating credential-stuffing attacks. Okta has observed suspicious activity that started on April 15, 2024. Review tenant logs for unexpected fcoa and scoa events.
Enabled: true
Severity: High
Runbook: If a user password was compromised in a credential stuffing attack, the user's credentials should be rotated immediately out of an abundance of caution.
Reference: https://sec.okta.com/articles/2024/05/detecting-cross-origin-authentication-credential-stuffing-attacks
DedupPeriodMinutes: 60
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when the condition below holds.
Condition
data.typeis one ofscoa,fcoa
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.type | in |
| field:"data.type" kind:in |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
type | data.type |
p_source_label |
Response runbook
If a user password was compromised in a credential stuffing attack, the user's credentials should be rotated immediately out of an abundance of caution.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"audience": "https://shared.app-api.clientdomain.com",
"client_id": "EmEDkk1wKV0bmzZut3rbEC5vxBE6UiZV",
"client_name": "App Frontend",
"connection": "Username-Password-Authentication",
"connection_id": "con_BvGURiLLdngYaT0D",
"date": "2024-10-29 18:52:51.953000000",
"description": "Unable to configure verification page.",
"details": {
"body": {},
"connection": "Username-Password-Authentication",
"error": {
"message": "Unable to configure verification page.",
"oauthError": "server_error",
"type": "oauth-authorization"
},
"qs": {
"_csrf": "TUReBWZ8-Fp9mvFrk6S3beuGrvKIkZVFfcKk",
"_intstate": "deprecated",
"audience": "https://shared.app-api.clientdomain.com",
"auth0Client": "eyJuYW1lIjoibG9jay5qcyIsInZlcnNpb24iOiIxMi4nYjOnsiYXV0aDAuanMiOiI5LjI2LjAifX0=",
"client_id": "EmEDkk1wKV0bmzZut3rbE0C5vxBE6UiZV",
"code_challenge": "oDe_o-4xT4_qdBvbbDiHPlVyoNKglqtNKqYrzcZt72M",
"code_challenge_method": "S256",
"connection": "Username-Password-Authentication",
"login_hint": "",
"login_ticket": "Uyqi3p1wDRZIWomeW3XxbjmSiBYNHzT8",
"nonce": "eW9wRjRhTFpMNlYyNHNJT1NvRm1jUUl0sM2ZxYk80azZILjdSVnBMcy14cg==",
"protocol": "oauth2",
"realm": "Username-Password-Authentication",
"redirect_uri": "https://redirect.app.clientdomain.com",
"response_mode": "query",
"response_type": "code",
"scope": "openid profile email offline_access",
"screen_hint": "login",
"state": "hKFo2SBPSW1RRnlhcjhxUVJZLUVwNzI0SzVjM3ItT10E4NXdMdKFupWxvZ2luo3RpZNkgdWtpQXVpakxnRlZ5Tm1ER2k4a0szTXZXLXNFSzQ5cFajY2lk2SBFbUVEa2sxd0tWMGJtelp1dDNyYkVDNXZ4QkU2VWlaVg"
},
"session_id": "OJ0d2L-gDTvkmwEctP8d3XwtLD8Yu1qh"
},
"hostname": "auth.clientdomain.com",
"ip": "2605:59c8:3075:214:d003:e902:2b01:dc14",
"log_id": "90020241029185251974499000000000000001223372087732751235",
"scope": [
"openid",
"profile",
"email",
"offline_access"
],
"type": "fcoa",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
},
"log_id": "90020241029185251974499000000000000001223372087732751235"
}
Auth0 CIC Credential Stuffing Query
#Okta has determined that the cross-origin authentication feature in Customer Identity Cloud (CIC) is prone to being targeted by threat actors orchestrating credential-stuffing attacks. Okta has observed suspicious activity that started on April 15, 2024. Review tenant logs for unexpected fcoa, scoa, and pwd_leak events. https://sec.okta.com/articles/2024/05/detecting-cross-origin-authentication-credential-stuffing-attacks
Rule specification
AnalysisType: saved_query
QueryName: "Auth0 CIC Credential Stuffing Query"
Description: Okta has determined that the cross-origin authentication feature in Customer Identity Cloud (CIC) is prone to being targeted by threat actors orchestrating credential-stuffing attacks. Okta has observed suspicious activity that started on April 15, 2024. Review tenant logs for unexpected fcoa, scoa, and pwd_leak events. https://sec.okta.com/articles/2024/05/detecting-cross-origin-authentication-credential-stuffing-attacks
SnowflakeQuery: |-
SELECT
*
FROM
panther_logs.public.auth0_events
WHERE
data:type in ('fcoa', 'scoa', 'pwd_leak')
and p_occurs_between('2024-04-14', current_timestamp)
DatabricksQuery: |-
SELECT
*
FROM
panther_logs.auth0_events
WHERE
data:type in ('fcoa', 'scoa', 'pwd_leak')
and p_occurs_between('2024-04-14', current_timestamp)
Stages and Predicates
Stage 1: source
Stage 2: filter
data:typeis one offcoa,scoa,pwd_leak
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 |
|---|---|---|---|
data:type | in |
| field:"data:type" kind:in |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field |
|---|
* |
Auth0 Custom Role Created
#An Auth0 User created a role in your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
return all(
[
data_description == "Create a role",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
request_body_name = event.deep_get(
"data", "details", "request", "body", "name", default="<NO_REQUEST_NAME_FOUND>"
)
request_body_description = event.deep_get(
"data", "details", "request", "body", default="<NO_REQUEST_BODY_FOUND>"
)
if "admin" in request_body_description or "admin" in request_body_name:
role_type = "admin"
else:
role_type = "custom"
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] created a "
f"role [{request_body_name}] with [{role_type}] "
f"permissions in your tenant [{p_source_label}]."
)
def severity(event):
request_body_name = event.deep_get(
"data", "details", "request", "body", "name", default="<NO_REQUEST_NAME_FOUND>"
)
request_body_description = event.deep_get(
"data", "details", "request", "body", "description", default=""
)
if "admin" in request_body_description or "admin" in request_body_name:
return "MEDIUM"
return "LOW"
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User created a role in your organization's tenant.
DisplayName: "Auth0 Custom Role Created"
Enabled: true
Filename: auth0_custom_role_created.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant if a user created a role without proper authorization.
Reference: https://auth0.com/docs/manage-users/access-control/configure-core-rbac/roles/create-roles
Severity: High
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.Custom.Role.Created"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisCreate a roledata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Create a role" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
name | data.details.request.body.name |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant if a user created a role without proper authorization.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-16 17:28:11.165000000",
"description": "Create a role",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0107c849078d8d889af711840197ba7c",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"description": "test",
"name": "test"
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "put",
"path": "/api/v2/guardian/policies",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": [],
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230516172812328948000000000000001223372037498448373",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230516172812328948000000000000001223372037498448373",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-16 17:28:11.165",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-16 17:29:28.904",
"p_row_id": "a2d1b1713461e7a5f1b08f991886e402",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Tenant Label"
}
Auth0 Delete Tenant Member
#A tenant member was deleted.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Exfiltration |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
return all(
[
is_auth0_config_event(event),
data_description == "Delete tenant member",
]
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Filename: auth0_delete_tenant_member.py
RuleID: Auth0.Delete.TenantMember
DisplayName: Auth0 Delete Tenant Member
Enabled: true
LogTypes:
- Auth0.Events
Severity: Info
CreateAlert: false
Reports:
MITRE ATT&CK:
- TA0010:T1041
Description: A tenant member was deleted.
Reference:
https://github.com/auth0/auth0-customer-detections/blob/main/detections/risk_of_tenant_takeover.yml
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.details.request.channelishttps://manage.auth0.com/data.descriptionisDelete tenant member
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Delete tenant member" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-10 10:27:51.149000000",
"description": "Delete tenant member",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000311abf72f7a0ce7a303592"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77",
"roles": [
"owner",
"user"
]
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/api/v2/integrations/installed",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "signup_pwd_leak",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452"
}
Auth0 Fraud Risk by Volume
#Detects a surge in either failed, successful or suspicious login attempts using leaked passwords over a window of time and a threshold. Exceeding set threshold may indicate potential fraud.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Detection logic
from panther_auth0_helpers import auth0_alert_context
SUSPICIOUS_EVENT_TYPES = (
"fs",
"ss",
"signup_pwd_leak",
)
def rule(event):
return event.deep_get("data", "type") in SUSPICIOUS_EVENT_TYPES
def title(event):
event_type = event.deep_get("data", "type")
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] had a surge of suspicious [{event_type}] event in "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
RuleID: "Auth0.FraudRisk.Volume"
Filename: auth0_fraud_risk_volume.py
LogTypes:
- Auth0.Events
DisplayName: "Auth0 Fraud Risk by Volume"
Description: Detects a surge in either failed, successful or suspicious login attempts using leaked passwords over a window of time and a threshold. Exceeding set threshold may indicate potential fraud.
Enabled: true
Severity: High
Reports:
MITRE ATT&CK:
- TA0003:T1136
Reference: https://github.com/auth0/auth0-customer-detections/blob/main/detections/risk_of_signup_fraud_by_volume.yml
DedupPeriodMinutes: 60
Threshold: 20
Stages and Predicates
Fires on Auth0.Events events when the condition below holds.
Condition
data.typeis one offs,ss,signup_pwd_leak
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.type | in |
| field:"data.type" kind:in |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
type | data.type |
p_source_label |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-10 10:27:51.149000000",
"description": "Someone behind the IP address ip attempted to login with a leaked password.",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000311abf72f7a0ce7a303592"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/api/v2/integrations/installed",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "signup_pwd_leak",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452"
}
Auth0 Integration Installed
#An Auth0 integration was installed from the auth0 action library.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
return all(
[
data_description == "Install an available integration",
request_path == "/api/v2/integrations/installed",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] installed an integration from the actions library for "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 integration was installed from the auth0 action library.
DisplayName: "Auth0 Integration Installed"
Enabled: true
Filename: auth0_integration_installed.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://auth0.com/blog/actions-integrations-are-now-ga/
Severity: Info
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.Integration.Installed"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisInstall an available integrationdata.details.request.pathis/api/v2/integrations/installeddata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Install an available integration" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/integrations/installed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-23 20:47:51.149000000",
"description": "Install an available integration",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "e6343ec1d24a41e6bd43a6be748cac11"
},
"strategy": "jwt",
"user": {
"email": "homer.simpson@yourcompany.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/api/v2/integrations/installed",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "826b85e235b6f5cbd8fd85ab18dfb703",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Leaked Password Login Attempt
#Detect Auth0 Leaked Password Login Attempt
Detection logic
from panther_core import PantherEvent
def rule(event: PantherEvent) -> bool:
return event.deep_get("data", "type") == "pwd_leak"
def title(event: PantherEvent) -> str:
ip_address = event.deep_get("data", "ip", default="NO_IP_FOUND")
user_name = event.deep_get("data", "user_name", default="NO_USERNAME")
event_title = (
"Someone behind the IP address {} attempted to login with a leaked password "
"with username {}"
)
return event_title.format(ip_address, user_name)
Rule specification
AnalysisType: rule
Description: Detect Auth0 Leaked Password Login Attempt
DisplayName: "Auth0 Leaked Password Login Attempt"
Enabled: true
Filename: auth0_leaked_password_login_attempt.py
Severity: Medium
DedupPeriodMinutes: 60
Threshold: 1
LogTypes:
- Auth0.Events
RuleID: "Auth0.Leaked.Password.Login.Attempt"
Stages and Predicates
Fires on Auth0.Events events when the condition below holds.
Condition
data.typeispwd_leak
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.type | eq |
| field:"data.type" kind:eq value:"pwd_leak" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
ip | data.ip |
user_name | data.user_name |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "11Qpq1o8fbGgnZuFJnQCyjuC1ll8YFt0",
"connection": "Username-Password-Authentication",
"connection_id": "con_BvGURiLLdngYaT0D",
"date": "2025-10-01 05:39:16.467000000",
"description": "Someone behind the IP address: 2601:140:9702:ee80:0000:1f55:93a7:e970 attempted to login with a leaked password. A shield to prevent this action was enabled, further attempts are blocked.",
"hostname": "auth.clientdomain.com",
"ip": "2601:140:9702:ee80:9049:1f55:0000:e970",
"log_id": "90020251001053916537654000000000000001223372122475524001",
"type": "pwd_leak",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"user_id": "",
"user_name": "denethor@lotr.com"
},
"log_id": "90020251001053916537654000000000000001223372122475524001"
}
Auth0 Limit Detections
#Detect Auth0 Limit Logs
Detection logic
from panther_core import PantherEvent
SUSPICIOUS_EVENT_TYPES = (
"api_limit",
"gd_otp_rate_limit_exceed",
"gd_recovery_rate_limit_exceed",
"limit_delegation",
"limit_mu",
"limit_sul",
"limit_wc",
)
EVENT_TITLES = (
"The maximum number of requests to the Authentication or Management APIs has been "
"reached for {}",
"Too many MFA failures occured for {}",
"{} has entered a wrong recovery code too many times",
"Rate limit exceeded to the delegation token endpoint by {}",
"{} IP address is blocked because it attempted too many sign-ups or failed logins: {}",
"{} is temporarily blocked from logging in because they reached the maximum logins from {}",
"{} IP address is blocked because it reached the maximum failed login attempts into a "
"single account: {}",
)
def rule(event: PantherEvent) -> bool:
return event.deep_get("data", "type") in SUSPICIOUS_EVENT_TYPES
def title(event: PantherEvent) -> str:
limit_mu_index = SUSPICIOUS_EVENT_TYPES.index("limit_mu")
limit_sul_index = SUSPICIOUS_EVENT_TYPES.index("limit_sul")
limit_wc_index = SUSPICIOUS_EVENT_TYPES.index("limit_wc")
event_type = event.deep_get("data", "type")
event_index = SUSPICIOUS_EVENT_TYPES.index(event_type)
event_title = EVENT_TITLES[event_index]
# limit_mu or limit_wc
if event_index in {limit_mu_index, limit_wc_index}:
ip_address = event.deep_get("data", "ip", default="NO_IP_FOUND")
username = event.deep_get("data", "user_name", default="NO_USER_FOUND")
return event_title.format(ip_address, username)
# limit_sul
if event_index == limit_sul_index:
ip_address = event.deep_get("data", "ip", default="NO_IP_FOUND")
username = event.deep_get("data", "user_name", default="NO_USER_FOUND")
return event_title.format(username, ip_address)
# other cases have only "user_name" field in their titles
username = event.deep_get("data", "user_name", default="NO_USER_FOUND")
return event_title.format(username)
Rule specification
AnalysisType: rule
Description: Detect Auth0 Limit Logs
DisplayName: "Auth0 Limit Detections"
Enabled: true
Filename: auth0_limits.py
Severity: Medium
DedupPeriodMinutes: 60
Threshold: 1
LogTypes:
- Auth0.Events
RuleID: "Auth0.Limits"
Stages and Predicates
Fires on Auth0.Events events when the condition below holds.
Condition
data.typeis one ofapi_limit,gd_otp_rate_limit_exceed,gd_recovery_rate_limit_exceed,limit_delegation,limit_mu
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.type | in |
| field:"data.type" kind:in |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
ip | data.ip |
user_name | data.user_name |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "11Qpq1o8fbGgnZuFJnQCyjuC1ll8YFt0",
"connection": "Username-Password-Authentication",
"connection_id": "con_BvGURiLLdngYaT0D",
"date": "2025-09-30 21:23:49.689000000",
"description": "User (john@justice.org) attempted 10 consecutive logins unsuccessfully. Brute force protection is enabled for this connection, further attempts are blocked from this IP address for this user.",
"hostname": "auth.clientdomain.com",
"ip": "1.2.3.4",
"log_id": "90020250930212349746493000000000000001223372122436618809",
"type": "limit_wc",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"user_id": "",
"user_name": "john@justice.org"
},
"log_id": "90020250930212349746493000000000000001223372122436618809"
}
Auth0 mfa factor enabled
#An Auth0 user enabled an mfa factor in your organization's mfa settings.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
description = event.deep_get("data", "description", default="<NO_DESCRIPTION_FOUND>")
enabled = event.deep_get("data", "details", "response", "body", "enabled")
return all(
[
description == "Update a Multi-factor Authentication Factor",
enabled is True,
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
path = event.deep_get("data", "details", "request", "path", default="<NO_PATH_FOUND>")
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] enabled mfa factor settings for [{path}] "
f"in your organization’s tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 user enabled an mfa factor in your organization's mfa settings.
DisplayName: "Auth0 mfa factor enabled"
Enabled: true
Filename: auth0_mfa_factor_setting_enabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://auth0.com/docs/secure/multi-factor-authentication/multi-factor-authentication-factors
Severity: Info
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.MFA.Factor.Setting.Enabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUpdate a Multi-factor Authentication Factordata.details.response.body.enabledistruedata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Update a Multi-factor Authentication Factor" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.response.body.enabled | eq |
| field:"data.details.response.body.enabled" kind:eq value:"true" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
path | data.details.request.path |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-15 21:55:18.060000000",
"description": "Update a Multi-factor Authentication Factor",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "949869e066205b5076e6df203fdd7b9b",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"AfterAuthentication": false
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "patch",
"path": "/api/v2/risk-assessment/config",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": {
"Enabled": true
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230515215719063964000000000000001223372037488829643",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230515215719063964000000000000001223372037488829643",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-15 21:55:18.06",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-15 21:58:28.629",
"p_row_id": "42b742dba9d5f3f284d49b971814",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Tenant Label"
}
Auth0 MFA Policy Disabled
#An Auth0 User disabled MFA for your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
request_body = event.deep_get("data", "details", "request", "body", default=[-1])
return all(
[
data_description == "Set the Multi-factor Authentication policies",
request_path == "/api/v2/guardian/policies",
request_body == [],
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] set mfa requirement settings to 'Never' for your "
f"organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User disabled MFA for your organization's tenant.
DisplayName: "Auth0 MFA Policy Disabled"
Enabled: true
Filename: auth0_mfa_policy_disabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://auth0.com/docs/secure/multi-factor-authentication/enable-mfa#:~:text=prompted%20for%20MFA.-,Never,-%3A%20MFA%20is%20not
Severity: High
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.MFA.Policy.Disabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisSet the Multi-factor Authentication policiesdata.details.request.pathis/api/v2/guardian/policiesdata.details.request.bodyis[]data.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Set the Multi-factor Authentication policies" |
data.details.request.body | eq |
| field:"data.details.request.body" kind:eq value:"[]" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/guardian/policies" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-16 17:28:11.165000000",
"description": "Set the Multi-factor Authentication policies",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0107c849078d8d889af711840197ba7c",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": [],
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "put",
"path": "/api/v2/guardian/policies",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": [],
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230516172812328948000000000000001223372037498448373",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230516172812328948000000000000001223372037498448373",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-16 17:28:11.165",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-16 17:29:28.904",
"p_row_id": "a2d1b1713461e7a5f1b08f991886e402",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Tenant Label"
}
Auth0 MFA Policy Enabled
#An Auth0 User enabled MFA Policy for your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
return all(
[
data_description == "Set the Multi-factor Authentication policies",
request_path == "/api/v2/guardian/policies",
is_auth0_config_event(event),
]
)
def title(event):
user_email = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
request_body = event.deep_get("data", "details", "request", "body", default=[])
if "all-applications" in request_body:
setting_change = "Always Require"
if "confidence-score" in request_body:
setting_change = "Use Adaptive MFA"
else:
setting_change = "Unknown"
return (
f"Auth0 user [{user_email}] set the "
f"mfa policies in your organization to [{setting_change}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User enabled MFA Policy for your organization's tenant.
DisplayName: "Auth0 MFA Policy Enabled"
Enabled: true
Filename: auth0_mfa_policy_enabled.py
Runbook: Assess if this was done by the user for a valid business reason and was expected. This alert indicates a setting change that aligns with best security practices, follow-up may be unnecessary.
Reference: https://auth0.com/docs/secure/multi-factor-authentication/enable-mfa#:~:text=In%20the-,Define%20policies,-section%2C%20select%20a
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.MFA.Policy.Enabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisSet the Multi-factor Authentication policiesdata.details.request.pathis/api/v2/guardian/policiesdata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Set the Multi-factor Authentication policies" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/guardian/policies" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
Response runbook
Assess if this was done by the user for a valid business reason and was expected. This alert indicates a setting change that aligns with best security practices, follow-up may be unnecessary.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-16 17:26:16.782000000",
"description": "Set the Multi-factor Authentication policies",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0107c849078d8d889af711840197ba7c",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": [
"all-applications"
],
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "put",
"path": "/api/v2/guardian/policies",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": [
"all-applications"
],
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230515215719063964000000000000001223372037488829643",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230515215719063964000000000000001223372037488829643",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-16 17:26:16.782",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-16 17:28:28.572",
"p_row_id": "2660c447622fa4c3dbb08f9918979102",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 MFA Risk Assessment Disabled
#An Auth0 User disabled the mfa risk assessment setting for your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
request_body = event.deep_get(
"data", "details", "request", "body", "AfterAuthentication", default=[]
)
return all(
[
data_description == "Updates risk assessment configs",
request_path == "/api/v2/risk-assessment/config",
request_body is False,
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] disabled mfa risk assessment settings for your "
f"organization’s tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User disabled the mfa risk assessment setting for your organization's tenant.
DisplayName: "Auth0 MFA Risk Assessment Disabled"
Enabled: true
Filename: auth0_mfa_risk_assessment_disabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://auth0.com/docs/secure/multi-factor-authentication/enable-mfa#:~:text=Always%20policy%2C%20the-,MFA%20Risk%20Assessors,-section%20appears.%20By
Severity: High
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.MFA.Risk.Assessment.Disabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUpdates risk assessment configsdata.details.request.pathis/api/v2/risk-assessment/configdata.details.request.body.AfterAuthenticationisfalsedata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Updates risk assessment configs" |
data.details.request.body.AfterAuthentication | eq |
| field:"data.details.request.body.AfterAuthentication" kind:eq value:"false" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/risk-assessment/config" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-15 21:55:18.060000000",
"description": "Updates risk assessment configs",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "949869e066205b5076e6df203fdd7b9b",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"AfterAuthentication": false
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "patch",
"path": "/api/v2/risk-assessment/config",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": {
"AfterAuthentication": false,
"BeforeLoginPrompt": false,
"BeforeLoginPromptMonitoring": false
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230515215719063964000000000000001223372037488829643",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230515215719063964000000000000001223372037488829643",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-15 21:55:18.06",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-15 21:58:28.629",
"p_row_id": "42b742dba9d5f3f284d49b971814",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Tenant Label"
}
Auth0 MFA Risk Assessment Enabled
#An Auth0 User enabled the mfa risk assessment setting for your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
request_body = event.deep_get(
"data", "details", "request", "body", "AfterAuthentication", default=[]
)
return all(
[
data_description == "Updates risk assessment configs",
request_path == "/api/v2/risk-assessment/config",
request_body is True,
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] enabled mfa risk assessment settings for your "
f"organization’s tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User enabled the mfa risk assessment setting for your organization's tenant.
DisplayName: "Auth0 MFA Risk Assessment Enabled"
Enabled: true
Filename: auth0_mfa_risk_assessment_enabled.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant when enabling this setting as it's in the best security interest for your organization's security posture.
Reference: https://auth0.com/docs/secure/multi-factor-authentication/enable-mfa#:~:text=Always%20policy%2C%20the-,MFA%20Risk%20Assessors,-section%20appears.%20By
Severity: Info
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.MFA.Risk.Assessment.Enabled"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUpdates risk assessment configsdata.details.request.pathis/api/v2/risk-assessment/configdata.details.request.body.AfterAuthenticationistruedata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Updates risk assessment configs" |
data.details.request.body.AfterAuthentication | eq |
| field:"data.details.request.body.AfterAuthentication" kind:eq value:"true" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/risk-assessment/config" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant when enabling this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-15 21:55:18.060000000",
"description": "Updates risk assessment configs",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "949869e066205b5076e6df203fdd7b9b",
"scopes": [
"create:actions",
"create:actions_log_sessions",
"create:authentication_methods",
"create:client_credentials",
"create:client_grants",
"create:clients",
"create:connections",
"create:custom_domains",
"create:email_provider",
"create:email_templates",
"create:guardian_enrollment_tickets",
"create:integrations",
"create:log_streams",
"create:organization_connections",
"create:organization_invitations",
"create:organization_member_roles",
"create:organization_members",
"create:organizations",
"create:requested_scopes",
"create:resource_servers",
"create:roles",
"create:rules",
"create:shields",
"create:signing_keys",
"create:tenant_invitations",
"create:test_email_dispatch",
"create:users",
"delete:actions",
"delete:anomaly_blocks",
"delete:authentication_methods",
"delete:branding",
"delete:client_credentials",
"delete:client_grants",
"delete:clients",
"delete:connections",
"delete:custom_domains",
"delete:device_credentials",
"delete:email_provider",
"delete:email_templates",
"delete:grants",
"delete:guardian_enrollments",
"delete:integrations",
"delete:log_streams",
"delete:organization_connections",
"delete:organization_invitations",
"delete:organization_member_roles",
"delete:organization_members",
"delete:organizations",
"delete:owners",
"delete:requested_scopes",
"delete:resource_servers",
"delete:roles",
"delete:rules",
"delete:rules_configs",
"delete:shields",
"delete:tenant_invitations",
"delete:tenant_members",
"delete:tenants",
"delete:users",
"read:actions",
"read:anomaly_blocks",
"read:attack_protection",
"read:authentication_methods",
"read:branding",
"read:checks",
"read:client_credentials",
"read:client_grants",
"read:client_keys",
"read:clients",
"read:connections",
"read:custom_domains",
"read:device_credentials",
"read:email_provider",
"read:email_templates",
"read:email_triggers",
"read:entity_counts",
"read:grants",
"read:guardian_factors",
"read:insights",
"read:integrations",
"read:log_streams",
"read:logs",
"read:mfa_policies",
"read:organization_connections",
"read:organization_invitations",
"read:organization_member_roles",
"read:organization_members",
"read:organizations",
"read:prompts",
"read:requested_scopes",
"read:resource_servers",
"read:roles",
"read:rules",
"read:rules_configs",
"read:shields",
"read:signing_keys",
"read:stats",
"read:tenant_invitations",
"read:tenant_members",
"read:tenant_settings",
"read:triggers",
"read:users",
"run:checks",
"update:actions",
"update:attack_protection",
"update:authentication_methods",
"update:branding",
"update:client_credentials",
"update:client_grants",
"update:client_keys",
"update:clients",
"update:connections",
"update:custom_domains",
"update:email_provider",
"update:email_templates",
"update:email_triggers",
"update:guardian_factors",
"update:integrations",
"update:log_streams",
"update:mfa_policies",
"update:organization_connections",
"update:organizations",
"update:prompts",
"update:requested_scopes",
"update:resource_servers",
"update:roles",
"update:rules",
"update:rules_configs",
"update:shields",
"update:signing_keys",
"update:tenant_members",
"update:tenant_settings",
"update:triggers",
"update:users"
]
},
"strategy": "jwt",
"user": {
"email": "user.name@yourcompany.io",
"name": "User Name",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"AfterAuthentication": true
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "patch",
"path": "/api/v2/risk-assessment/config",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": {
"AfterAuthentication": true,
"BeforeLoginPrompt": false,
"BeforeLoginPromptMonitoring": false
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230515215719063964000000000000001223372037488829643",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230515215719063964000000000000001223372037488829643"
}
Auth0 New Admin Invited
#A new admin invitation was issued.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
roles = event.deep_get("data", "details", "request", "body", "roles", default="<NO_ROLE_FOUND>")
return all(
[
is_auth0_config_event(event),
data_description == "Create tenant invitations for a given client",
"owner" in roles,
]
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Filename: auth0_new_admin_invited.py
RuleID: Auth0.NewAdmin.Invitation
DisplayName: Auth0 New Admin Invited
Enabled: true
LogTypes:
- Auth0.Events
Severity: Info
CreateAlert: false
Reports:
MITRE ATT&CK:
- TA0003:T1136
Description: A new admin invitation was issued.
Reference:
https://github.com/auth0/auth0-customer-detections/blob/main/detections/risk_of_tenant_takeover.yml
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.details.request.channelishttps://manage.auth0.com/data.descriptionisCreate tenant invitations for a given clientdata.details.request.body.rolescontainsowner
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Create tenant invitations for a given client" |
data.details.request.body.roles | contains |
| field:"data.details.request.body.roles" kind:contains value:"owner" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-10 10:27:51.149000000",
"description": "Create tenant invitations for a given client",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000311abf72f7a0ce7a303592"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77",
"roles": [
"owner",
"user"
]
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/api/v2/integrations/installed",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "signup_pwd_leak",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452"
}
Auth0 New Admin Invited WITH Tenant Member Account Deletion
#A user was invited as admin and shortly after deleted tenant member accounts. This may indicate account takeover attempts.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Rule specification
AnalysisType: correlation_rule
RuleID: "Auth0.AdminInvited.WITH.TenantMemberDeletion"
DisplayName: "Auth0 New Admin Invited WITH Tenant Member Account Deletion"
Enabled: false
Tags:
- Auth0
Severity: High
Reports:
MITRE ATT&CK:
- TA0003:T1098
- TA0003:T1136
Description: A user was invited as admin and shortly after deleted tenant member accounts. This may indicate account takeover attempts.
Detection:
- Group:
- ID: CreateAdmin
RuleID: Auth0.NewAdmin.Invitation
- ID: DeleteUser
RuleID: Auth0.Delete.TenantMember
MinMatchCount: 2
MatchCriteria:
field_name:
- GroupID: CreateAdmin
Match: p_alert_context.actor.email
- GroupID: DeleteUser
Match: p_alert_context.actor.email
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
LookbackWindowMinutes: 1800
Stages and Predicates
Fires when the steps below all occur within 30h, correlated by p_alert_context.actor.email. Each step needs one match unless a higher minimum is shown.
Stage 1: step CreateAdmin
References detection Auth0 New Admin Invited.
Stage 2: step DeleteUser
References detection Auth0 Delete Tenant Member (min 2 matches).
Auth0 Post Login Action Flow Updated
#An Auth0 User updated a post login action flow for your organization's tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
from panther_base_helpers import deep_get
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
request_path = event.deep_get(
"data", "details", "request", "path", default="<NO_REQUEST_PATH_FOUND>"
)
return all(
[
data_description == "Update trigger bindings",
request_path == "/api/v2/actions/triggers/post-login/bindings",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
request_bindings = event.deep_get("data", "details", "request", "body", "bindings", default=[])
response_bindings = event.deep_get(
"data", "details", "response", "body", "bindings", default=[]
)
actions_added_list = []
for binding in request_bindings:
if "display_name" in binding:
# check to see if actions were added to the flow
actions_added_list.append(binding.get("display_name", ""))
# otherwise, actions were removed from the action flow and we want
# to grab what's still present in the flow
actions_remaining_list = []
for binding in response_bindings:
if deep_get(binding, "display_name"):
actions_remaining_list.append(
deep_get(binding, "display_name", default="<NO_DISPLAYNAME>")
)
if actions_added_list:
return (
f"Auth0 User [{user}] added action(s) [{actions_added_list}] to a post-login action "
f"flow for your organization’s tenant [{p_source_label}]."
)
if actions_remaining_list:
return (
f"Auth0 User [{user}] removed action(s) "
f"to a post-login action flow for your organization’s tenant [{p_source_label}], "
f"remaining actions include [{actions_remaining_list}]."
)
# no actions remain in the flow
return (
f"Auth0 User [{user}] removed all actions "
f"from a post-login action flow for your organization’s tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: An Auth0 User updated a post login action flow for your organization's tenant.
DisplayName: "Auth0 Post Login Action Flow Updated"
Enabled: true
Filename: auth0_post_login_action_flow.py
Runbook: Assess if this was done by the user for a valid business reason. Be sure to replace any steps that were removed without authorization.
Reference: https://auth0.com/docs/customize/actions/flows-and-triggers/login-flow/api-object
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.Post.Login.Action.Flow"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUpdate trigger bindingsdata.details.request.pathis/api/v2/actions/triggers/post-login/bindingsdata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Update trigger bindings" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.details.request.path | eq |
| field:"data.details.request.path" kind:eq value:"/api/v2/actions/triggers/post-login/bindings" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be sure to replace any steps that were removed without authorization.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "XXX",
"client_name": "",
"date": "2023-05-23 20:53:36.557000000",
"description": "Update trigger bindings",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "XXX"
},
"strategy": "jwt",
"user": {
"email": "homer.simpson@yourcompany.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|XXX"
}
},
"body": {
"bindings": [
{
"display_name": "Password Rotation",
"ref": {
"type": "action_id",
"value": "XXX"
}
}
]
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "patch",
"path": "/api/v2/actions/triggers/post-login/bindings",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
},
"response": {
"body": {
"bindings": [
{
"action": {
"all_changes_deployed": false,
"created_at": "2023-04-24T19:33:44.217168082Z",
"current_version": {
"created_at": "2023-05-11T17:26:53.569382908Z",
"id": "c4c1d580-2f51-4d7b-afa5-ad4216f40ad3",
"runtime": "node16",
"status": "BUILT",
"updated_at": "2023-05-11T17:26:53.724617041Z"
},
"deployed_version": {
"code": "",
"created_at": "2023-05-11T17:26:53.569382908Z",
"dependencies": [],
"deployed": true,
"id": "c4c1d580-2f51-4d7b-afa5-ad4216f40ad3",
"runtime": "node16",
"secrets": [],
"status": "built",
"updated_at": "2023-05-11T17:26:53.724617041Z"
},
"id": "XXX",
"installed_integration_id": "XXX",
"integration": {
"catalog_id": "password-rotation",
"created_at": "2023-04-24T19:33:44.212805393Z",
"current_release": {
"id": "",
"semver": {}
},
"description": "This Action allows you to configure the number of days a password is valid before it expires and the user must rotate it.\n",
"feature_type": "action",
"id": "64bee519-818f-4473-ab08-7c380f28da77",
"logo": "https://cdn.auth0.com/marketplace/catalog/content/assets/creators/auth0/auth0-avatar.png",
"name": "Password Rotation",
"partner_id": "XXX",
"short_description": "Enforce Users to Rotate Passwords",
"terms_of_use_url": "https://cdn.auth0.com/website/legal/files/mktplace/auth0-integration.pdf",
"updated_at": "2023-05-11T17:26:53.560940001Z",
"url_slug": "auth-0-password-rotation"
},
"name": "Password Rotation v1",
"supported_triggers": [
{
"id": "post-login",
"status": "CURRENT",
"version": "v3"
}
],
"updated_at": "2023-04-24T19:33:44.217168082Z"
},
"created_at": "2023-05-23T20:53:36.528608347Z",
"display_name": "Password Rotation",
"id": "a12b9e2a-ec0f-4060-b476-18547030088a",
"trigger_id": "post-login",
"updated_at": "2023-05-23T20:53:36.528608347Z"
}
]
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "XXX",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"user_id": "google-oauth2|XXX"
},
"log_id": "XXX",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Push Notification Fatigue
#Push notifications threshold exceeded for a user. It may indicate a push notification fatigue attempt.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_type = event.deep_get("data", "type", default="<NO_DATA_TYPE_FOUND>")
return all(
[
data_type == "gd_send_pn",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
return (
f"Auth0 User [{user}] has received an excessive number of MFA push notifications,"
f"possible MFA fatigue detected"
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: Push notifications threshold exceeded for a user. It may indicate a push notification fatigue attempt.
DisplayName: "Auth0 Push Notification Fatigue"
Enabled: true
Filename: auth0_push_notification_fatigue.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://github.com/auth0/auth0-customer-detections/tree/main/detections
Severity: High
Reports:
MITRE ATT&CK:
- TA0006:T1621
DedupPeriodMinutes: 30
LogTypes:
- Auth0.Events
RuleID: "Auth0.PushNotification.Fatigue"
Threshold: 5
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.typeisgd_send_pndata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.type | eq |
| field:"data.type" kind:eq value:"gd_send_pn" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-03 14:09:32.149000000",
"description": "Push notification for MFA successfully sent",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000ecaf1bfbadb06900d22049"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"enabled": true
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/v2/attack-protection/push-notification",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": [],
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "gd_send_pn",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "00000000004a745ce33b57be383c543e",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Rapid Dynamic Client Creation
#Detects a spike in registered dynamic clients. This can indicate attempts to use such dynamic clients for malicious purposes.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
data_type = event.deep_get("data", "type", default="<NO_DATA_TYPE_FOUND>")
return all(
[
is_auth0_config_event(event),
data_type == "sapi",
data_description == "Dynamic client registration",
]
)
def title(event):
client_id = event.deep_get(
"data", "details", "response", "body", "client_id", default="<NO_CLIENT_ID_FOUND"
)
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 Significant number of Dynamic Client registration of [{data_description}] "
f"with client id [{client_id}] in "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
RuleID: "Auth0.Rapid.DynamicClient.Creation"
Filename: auth0_rapid_dynamic_client_creation.py
LogTypes:
- Auth0.Events
DisplayName: "Auth0 Rapid Dynamic Client Creation"
Description: Detects a spike in registered dynamic clients. This can indicate attempts to use such dynamic clients for malicious purposes.
Severity: High
Reports:
MITRE ATT&CK:
- TA0003:T1136
Enabled: True
Reference: https://github.com/auth0/auth0-customer-detections/blob/main/detections/rapid_creation_of_clients_with_dynamic_registration.yml
DedupPeriodMinutes: 60
Threshold: 15
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.details.request.channelishttps://manage.auth0.com/data.typeissapidata.descriptionisDynamic client registration
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Dynamic client registration" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.type | eq |
| field:"data.type" kind:eq value:"sapi" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
description | data.description |
client_id | data.details.response.body.client_id |
p_source_label |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-10 10:27:51.149000000",
"description": "Dynamic client registration",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000311abf72f7a0ce7a303592"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/api/v2/integrations/installed",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"client_id": "64bee519-818f-4473-ab08-7c380f28da77",
"integration_id": "64bee519-818f-4473-ab08-7c380f28da77"
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "sapi",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452"
}
Auth0 Refresh Token Reused
#A refresh token was reused.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
data_type = event.deep_get("data", "type", default="<NO_DATA_TYPE_FOUND>")
return all(
[
data_description
== "Unsuccessful Refresh Token exchange, reused refresh token detected",
data_type == "ferrt",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] attempted to reuse a refresh token for"
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: A refresh token was reused.
DisplayName: "Auth0 Refresh Token Reused"
Enabled: true
Filename: auth0_token_reuse.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://github.com/auth0/auth0-customer-detections/tree/main/detections
Severity: High
Reports:
MITRE ATT&CK:
- TA0006:T1528
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.RefreshToken.Reuse"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUnsuccessful Refresh Token exchange, reused refresh token detecteddata.typeisferrtdata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Unsuccessful Refresh Token exchange, reused refresh token detected" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
data.type | eq |
| field:"data.type" kind:eq value:"ferrt" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-03 14:09:32.149000000",
"description": "Unsuccessful Refresh Token exchange, reused refresh token detected",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "0000000000ecaf1bfbadb06900d22049"
},
"strategy": "jwt",
"user": {
"email": "denethor@lotr.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"enabled": true
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "post",
"path": "/v2/attack-protection/token-reuse",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": {
"password_reset_policy": false,
"passwordless_policy": false,
"policy": false
},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "ferrt",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "00000000004a745ce33b57be383c543e",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 Same Phone Number Shared Across Multiple Users as MFA
#Detecs when more than one user shares a phone number with another for MFA purposes. Attackers may register their phone number for multiple compromised accounts.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Detection logic
from panther_auth0_helpers import auth0_alert_context
def rule(event):
data_type = event.deep_get("data", "type", default="<NO_TYPE_FOUND>")
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
phone_number = str(
event.deep_get(
"data", "details", "authenticator", "phone_number", default="<NO_PHONE_NUMBER_FOUND>"
)
)
return (
data_type == "gd_enrollment_complete"
and data_description == "Guardian - Enrollment complete (sms)"
and bool(phone_number)
)
def unique(event):
return event.deep_get("data", "user_id", default="")
def dedup(event):
return str(
event.deep_get(
"data", "details", "authenticator", "phone_number", default="<NO_PHONE_NUMBER_FOUND>"
)
)
def title(event):
user_id = event.deep_get("data", "user_id", default="<NO_USER_ID_FOUND>")
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
phone_number = event.deep_get(
"data", "details", "authenticator", "phone_number", default="<NO_PHONE_NUMBER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] having user_id [{user_id}] "
f"shares phone number [{phone_number}] as MFA in "
f"your organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
Description: Detecs when more than one user shares a phone number with another for MFA purposes. Attackers may register their phone number for multiple compromised accounts.
DisplayName: "Auth0 Same Phone Number Shared Across Multiple Users as MFA"
Enabled: true
Filename: auth0_same_phone_mfa_multiple_users.py
Runbook: Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Reference: https://github.com/auth0/auth0-customer-detections/tree/main/detections/multiple_phone_numbers_are_registered_as_mfa.yml
Severity: High
Reports:
MITRE ATT&CK:
- TA0003:T1098
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.SamePhone.MultipleUsers.MFA"
Threshold: 2
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.typeisgd_enrollment_completedata.descriptionisGuardian - Enrollment complete (sms)data.details.authenticator.phone_numberis present
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Guardian - Enrollment complete (sms)" |
data.details.authenticator.phone_number | is_not_null | field:"data.details.authenticator.phone_number" kind:is_not_null | |
data.type | eq |
| field:"data.type" kind:eq value:"gd_enrollment_complete" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
user_id | data.user_id |
phone_number | data.details.authenticator.phone_number |
p_source_label |
Response runbook
Assess if this was done by the user for a valid business reason. Be vigilant to re-enable this setting as it's in the best security interest for your organization's security posture.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2025-10-03 14:09:32.149000000",
"description": "Guardian - Enrollment complete (sms)",
"details": {
"authenticator": {
"phone_number": 1234567891
},
"request": {
"auth": {
"credentials": {
"jti": "0000000000ecaf1bfbadb06900d22049"
},
"strategy": "jwt",
"user": {
"email": "eve@lexcorp.com",
"name": "Homer Simpson"
}
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36"
},
"response": {
"body": [],
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230523204756343781000000000000001223372037583230452",
"type": "gd_enrollment_complete",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1.2.3.4 Safari/537.36",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230523204756343781000000000000001223372037583230452",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-23 20:47:51.149",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-23 20:49:28.671",
"p_row_id": "00000000004a745ce33b57be383c543e",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}
Auth0 User Invitation Created
#Detection logic
import re
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
org_re = re.compile(r"^/api/v2/organizations/[^/\s]+/invitations$")
def rule(event):
if not is_auth0_config_event(event):
return False
return invitation_type(event) is not None
def title(event):
inv_type = invitation_type(event)
if inv_type == "tenant":
try:
invitee = event.deep_get("data", "details", "request", "body", "owners", default=[])[0]
except IndexError:
invitee = "<NO_INVITEE>"
elif inv_type == "organization":
invitee = event.deep_get("data", "details", "request", "body", "invitee", "email")
else:
invitee = "<NO_INVITEE>"
inviter = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_INVITER>"
)
source = event.get("p_source_label", "<NO_PSOURCE>")
return f"Auth0 User [{inviter}] invited [{invitee}] to {inv_type} [{source}]]"
def invitation_type(event):
path = event.deep_get("data", "details", "request", "path", default="")
if path == "/api/v2/tenants/invitations":
return "tenant"
if org_re.match(path):
return "organization"
return None
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
DisplayName: "Auth0 User Invitation Created"
Enabled: true
Filename: auth0_user_invitation_created.py
Reference: https://auth0.com/docs/manage-users/organizations/configure-organizations/invite-members
Severity: Info
CreateAlert: false
DedupPeriodMinutes: 60
LogTypes:
- Auth0.Events
RuleID: "Auth0.User.Invitation.Created"
Threshold: 1
Stages and Predicates
Fires on Auth0.Events events when the condition below holds.
Condition
data.details.request.channelishttps://manage.auth0.com/
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 |
|---|---|---|---|
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"_id": "90020230616045255729813000000000000001223372038324184656",
"client_id": "6xNLmMWZMYvMO3ZjQoN8siUWAbg3pnpA",
"client_name": "",
"date": "2023-06-16T04:52:50.663Z",
"description": "Create invitations to organization",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "81a67a5a3b2c4fb5cc2fcf38349456dd"
},
"strategy": "jwt",
"user": {
"email": "bob@panther.com",
"name": "Bob",
"user_id": "google-oauth2|115547599209686809398"
}
},
"body": {
"client_id": "KwJItGFu62zryEc4c8t5BQuwB1qdeDFa",
"invitee": {
"email": "larry@example.com"
},
"inviter": {
"name": "Larry Jones"
}
},
"channel": "https://manage.auth0.com/",
"ip": "123.123.123.123",
"method": "post",
"path": "/api/v2/organizations/org_tFmw9RlOUjoSkOf1/invitations",
"query": {},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
},
"response": {
"body": {
"client_id": "KwJItGFu62zryEc4c8t5BQuwB1qdeDFa",
"id": "uinv_DeLuEdgf3hjxRd0z",
"invitee": {
"email": "frank@example.com"
},
"inviter": {
"name": "Bob Jones"
}
},
"statusCode": 201
}
},
"id": "90020230616045255729813000000000000001223372038324184656",
"ip": "123.123.123.123",
"isMobile": false,
"log_id": "90020230616045255729813000000000000001223372038324184656",
"type": "sapi",
"user_agent": "Chrome 114.0.0 / Mac OS X 10.15.7",
"user_id": "google-oauth2|115547599209686809398"
},
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"auth0|6459776e974703f3a65dc258"
],
"p_event_time": "2023-05-15 16:13:53.609",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-15 16:15:28.555",
"p_row_id": "e20ac28001d19ac6df97b99618d4a207",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Auth0 Org Label"
}
Auth0 User Joined Tenant
#User accepted invitation from Auth0 member to join an Auth0 tenant.
Detection logic
from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event
def rule(event):
data_description = event.deep_get("data", "description", default="<NO_DATA_DESCRIPTION_FOUND>")
scopes = event.deep_get(
"data",
"details",
"request",
"auth",
"credentials",
"scopes",
default=["<NO_CREDENTIAL_SCOPE>"],
)
state = event.deep_get("data", "details", "request", "body", "state", default="<NO_STATE>")
return all(
[
data_description == "Update an invitation",
"update:tenant_invitations" in scopes,
state == "accepted",
is_auth0_config_event(event),
]
)
def title(event):
user = event.deep_get(
"data", "details", "request", "auth", "user", "email", default="<NO_USER_FOUND>"
)
p_source_label = event.get("p_source_label", "<NO_P_SOURCE_LABEL_FOUND>")
return (
f"Auth0 User [{user}] has accepted an invitation to join your "
f"organization's tenant [{p_source_label}]."
)
def alert_context(event):
return auth0_alert_context(event)
Rule specification
AnalysisType: rule
DisplayName: Auth0 User Joined Tenant
Description: User accepted invitation from Auth0 member to join an Auth0 tenant.
Enabled: true
Filename: auth0_user_joined_tenant.py
RuleID: Auth0.User.Joined.Tenant
Reference: https://auth0.com/docs/manage-users/organizations/configure-organizations/invite-members#send-membership-invitations:~:text=.-,Send%20membership%20invitations,-You%20can
Severity: Info
CreateAlert: false
LogTypes:
- Auth0.Events
Stages and Predicates
Fires on Auth0.Events events when all of the conditions below hold.
Condition
data.descriptionisUpdate an invitationdata.details.request.auth.credentials.scopescontainsupdate:tenant_invitationsdata.details.request.body.stateisaccepteddata.details.request.channelishttps://manage.auth0.com/
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data.description | eq |
| field:"data.description" kind:eq value:"Update an invitation" |
data.details.request.auth.credentials.scopes | contains |
| field:"data.details.request.auth.credentials.scopes" kind:contains value:"update:tenant_invitations" |
data.details.request.body.state | eq |
| field:"data.details.request.body.state" kind:eq value:"accepted" |
data.details.request.channel | eq |
| field:"data.details.request.channel" kind:eq value:"https://manage.auth0.com/" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | data.details.request.auth.user.email |
p_source_label |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"data": {
"client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr",
"client_name": "",
"date": "2023-05-15 16:17:00.128000000",
"description": "Update an invitation",
"details": {
"request": {
"auth": {
"credentials": {
"jti": "9da39f3d0b369356d2f4338ff13e4e8b",
"scopes": [
"update:tenant_invitations"
]
},
"strategy": "jwt",
"user": {
"email": "homer.simpson@yourcompany.com",
"name": "Homer Simpson",
"user_id": "google-oauth2|105261262156475850461"
}
},
"body": {
"state": "accepted",
"user": {
"email": "homer.simpson@yourcompany.com",
"id": "google-oauth2|105261262156475850461"
}
},
"channel": "https://manage.auth0.com/",
"ip": "12.12.12.12",
"method": "patch",
"path": "/api/v2/tenants/invitations/inv_TEyzbreI336AHrfU",
"query": {}
},
"response": {
"body": {},
"statusCode": 200
}
},
"ip": "12.12.12.12",
"log_id": "90020230515161703699125000000000000001223372037485126920",
"type": "sapi",
"user_id": "google-oauth2|105261262156475850461"
},
"log_id": "90020230515161703699125000000000000001223372037485126920",
"p_any_ip_addresses": [
"12.12.12.12"
],
"p_any_usernames": [
"google-oauth2|105261262156475850461"
],
"p_event_time": "2023-05-15 16:17:00.128",
"p_log_type": "Auth0.Events",
"p_parse_time": "2023-05-15 16:18:28.605",
"p_row_id": "6e94415d533cdcaac7ffc79618fb9b01",
"p_schema_version": 0,
"p_source_id": "b9031579-b2c5-45c2-b15c-632b995a4e36",
"p_source_label": "Org Auth0 Tenant Label"
}