Detection rules › Panther
Panther rules: asana
Asana Service Account Created
#An Asana service account was created by someone in your organization.
Detection logic
def rule(event):
return event.get("event_type", "<NO_EVENT_TYPE_FOUND>") == "service_account_created"
def title(event):
actor_email = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
svc_acct_name = event.deep_get("resource", "name", default="<SVC_ACCT_NAME_NOT_FOUND>")
return f"Asana user [{actor_email}] created a new service account [{svc_acct_name}]."
Rule specification
AnalysisType: rule
Description: An Asana service account was created by someone in your organization.
DisplayName: "Asana Service Account Created"
Enabled: true
Filename: asana_service_account_created.py
Runbook: Confirm this user acted with valid business intent and determine whether this activity was authorized.
Reference: https://help.asana.com/hc/en-us/articles/14217496838427-Service-Accounts
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Service.Account.Created"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when the condition below holds.
Condition
event_typeisservice_account_created
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event_type | eq |
| field:"event_type" kind:eq value:"service_account_created" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
name | resource.name |
Response runbook
Confirm this user acted with valid business intent and determine whether this activity was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@panther.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:28:18.396",
"details": {},
"event_category": "apps",
"event_type": "service_account_created",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Slack Service Account",
"resource_type": "user"
}
}
Asana Team Privacy Public
#An Asana team's privacy setting was changed to public to the organization (not public to internet)
Detection logic
def rule(event):
return (
event.get("event_type") == "team_privacy_settings_changed"
and event.deep_get("details", "new_value") == "public"
)
def title(event):
team = event.deep_get("resource", "name", default="<TEAM_NOT_FOUND>")
actor = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return f"Asana team [{team}] has been made public to the org by [{actor}]."
Rule specification
AnalysisType: rule
Description: An Asana team's privacy setting was changed to public to the organization (not public to internet)
DisplayName: "Asana Team Privacy Public"
Enabled: true
Filename: asana_team_privacy_public.py
Reference: https://help.asana.com/hc/en-us/articles/14211433439387-Team-permissions
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Team.Privacy.Public"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisteam_privacy_settings_changeddetails.new_valueispublic
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"public" |
event_type | eq |
| field:"event_type" kind:eq value:"team_privacy_settings_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
name | resource.name |
email | actor.email |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@panther.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:35:21.026",
"details": {
"new_value": "public"
},
"event_category": "access_control",
"event_type": "team_privacy_settings_changed",
"gid": "12345",
"p_log_type": "Asana.Audit",
"resource": {
"gid": "12345",
"name": "Example Team Name",
"resource_type": "team"
}
}
Asana Workspace Default Session Duration Never
#An Asana workspace's default session duration (how often users need to re-authenticate) has been changed to never.
Detection logic
def rule(event):
return (
event.get("event_type") == "workspace_default_session_duration_changed"
and event.deep_get("details", "new_value") == "never"
)
def title(event):
workspace = event.deep_get("resource", "name", default="<WORKSPACE_NOT_FOUND>")
actor = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return (
f"Asana workspace [{workspace}]'s default session duration "
f"has been set to never expire by [{actor}]."
)
Rule specification
AnalysisType: rule
Description: "An Asana workspace's default session duration (how often users need to re-authenticate) has been changed to never. "
DisplayName: "Asana Workspace Default Session Duration Never"
Enabled: true
Filename: asana_workspace_default_session_duration_never.py
Reference: https://help.asana.com/hc/en-us/articles/14218320495899-Manage-Session-Duration
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Default.Session.Duration.Never"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisworkspace_default_session_duration_changeddetails.new_valueisnever
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"never" |
event_type | eq |
| field:"event_type" kind:eq value:"workspace_default_session_duration_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
name | resource.name |
email | actor.email |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer@example.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:31:13.887",
"details": {
"new_value": "never",
"old_value": "14 days"
},
"event_category": "admin_settings",
"event_type": "workspace_default_session_duration_changed",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Acme Co",
"resource_type": "workspace"
}
}
Asana Workspace Email Domain Added
#A new email domain has been added to an Asana workspace. Reviewer should validate that the new domain is a part of the organization.
Detection logic
def rule(event):
return event.get("event_type") == "workspace_associated_email_domain_added"
def title(event):
workspace = event.deep_get("resource", "name", default="<WORKSPACE_NOT_FOUND>")
domain = event.deep_get("details", "new_value", default="<DOMAIN_NOT_FOUND>")
actor = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return f"Asana new email domain [{domain}] added to Workspace [{workspace}] by [{actor}]."
Rule specification
AnalysisType: rule
Description: "A new email domain has been added to an Asana workspace. Reviewer should validate that the new domain is a part of the organization. "
DisplayName: "Asana Workspace Email Domain Added"
Enabled: true
Filename: asana_workspace_email_domain_added.py
Reference: https://help.asana.com/hc/en-us/articles/15901227439515-Email-domain-management-for-Asana-organizations
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Email.Domain.Added"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when the condition below holds.
Condition
event_typeisworkspace_associated_email_domain_added
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event_type | eq |
| field:"event_type" kind:eq value:"workspace_associated_email_domain_added" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
new_value | details.new_value |
name | resource.name |
email | actor.email |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:30:26.15",
"details": {
"new_value": "test.com"
},
"event_category": "admin_settings",
"event_type": "workspace_associated_email_domain_added",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Example IO",
"resource_type": "workspace"
}
}
Asana Workspace Form Link Auth Requirement Disabled
#An Asana Workspace Form Link is a unique URL that allows you to create a task directly within a specific Workspace or Project in Asana, using a web form. Disabling authentication requirements may allow unauthorized users to create tasks.
Detection logic
def rule(event):
return event.get("event_type") == "workspace_form_link_authentication_required_disabled"
def title(event):
workspace = event.deep_get("resource", "name", default="<WORKSPACE_NOT_FOUND>")
actor = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return (
f"Asana Workspace [{workspace}] Form Link Auth Requirement " f" was disabled by [{actor}]."
)
Rule specification
AnalysisType: rule
Description: "An Asana Workspace Form Link is a unique URL that allows you to create a task directly within a specific Workspace or Project in Asana, using a web form. Disabling authentication requirements may allow unauthorized users to create tasks. "
DisplayName: "Asana Workspace Form Link Auth Requirement Disabled"
Enabled: true
Filename: asana_workspace_form_link_auth_requirement_disabled.py
Reference: https://help.asana.com/hc/en-us/articles/14111697664923-Forms-access-permissions#:~:text=SSO%2C%20SAML%2C%20or-,no%20authentication%20method,-).%20If%20no%20authentication
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Form.Link.Auth.Requirement.Disabled"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when the condition below holds.
Condition
event_typeisworkspace_form_link_authentication_required_disabled
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event_type | eq |
| field:"event_type" kind:eq value:"workspace_form_link_authentication_required_disabled" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
name | resource.name |
email | actor.email |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@simpsons.com",
"gid": "1234567890",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "1.2.3.4",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:32:00.922",
"details": {},
"event_category": "admin_settings",
"event_type": "workspace_form_link_authentication_required_disabled",
"gid": "1234567890",
"resource": {
"gid": "111234",
"name": "Simpsons Lab",
"resource_type": "workspace"
}
}
Asana Workspace Guest Invite Permissions Anyone
#Typically inviting guests to Asana is permitted by few users. Enabling anyone to invite guests can potentially lead to unauthorized users gaining access to Asana.
Detection logic
def rule(event):
return (
event.get("event_type") == "workspace_guest_invite_permissions_changed"
and event.deep_get("details", "new_value") == "anyone"
)
def title(event):
workspace = event.deep_get("resource", "name", default="<WORKSPACE_NOT_FOUND>")
actor = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return (
f"Asana Workspace [{workspace}] guest invite permissions "
f"changed to anyone by [{actor}]."
)
Rule specification
AnalysisType: rule
Description: Typically inviting guests to Asana is permitted by few users. Enabling anyone to invite guests can potentially lead to unauthorized users gaining access to Asana.
DisplayName: "Asana Workspace Guest Invite Permissions Anyone"
Enabled: true
Filename: asana_workspace_guest_invite_permissions_anyone.py
Reference: https://help.asana.com/hc/en-us/articles/14109494654875-Admin-console#:~:text=Google%20SSO%20password.-,Guest%20invite%20controls,-Super%20admins%20of
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Guest.Invite.Permissions.Anyone"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisworkspace_guest_invite_permissions_changeddetails.new_valueisanyone
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"anyone" |
event_type | eq |
| field:"event_type" kind:eq value:"workspace_guest_invite_permissions_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
name | resource.name |
email | actor.email |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:30:26.15",
"details": {
"new_value": "anyone",
"old_value": "admins_only"
},
"event_category": "admin_settings",
"event_type": "workspace_guest_invite_permissions_changed",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Example IO",
"resource_type": "workspace"
}
}
Asana Workspace New Admin
#Admin role was granted to the user who previously did not have admin permissions
Detection logic
from panther_asana_helpers import asana_alert_context
def rule(event):
new = event.deep_get("details", "new_value", default="")
old = event.deep_get("details", "old_value", default="")
return all(
[
event.get("event_type") == "user_workspace_admin_role_changed",
"admin" in new,
"admin" not in old,
]
)
def title(event):
a_c = asana_alert_context(event)
w_s = event.deep_get("details", "group", "name", default="<WS_NAME_NOT_FOUND>")
return (
f"Asana user [{a_c.get('resource_name')}] was made an admin "
f"in workspace [{w_s}] by [{a_c.get('actor')}]."
)
def alert_context(event):
return asana_alert_context(event)
Rule specification
AnalysisType: rule
Description: Admin role was granted to the user who previously did not have admin permissions
DisplayName: Asana Workspace New Admin
Enabled: true
Filename: asana_workspace_new_admin.py
Reference: https://help.asana.com/hc/en-us/articles/14141552580635-Admin-and-super-admin-roles-in-Asana
Severity: High
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.New.Admin"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisuser_workspace_admin_role_changeddetails.new_valuecontainsadmindetails.old_valuedoes not containadmin
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
details.old_value | contains | admin | excludes:details.old_value field:"details.old_value" value:"admin" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | contains |
| field:"details.new_value" kind:contains value:"admin" |
event_type | eq |
| field:"event_type" kind:eq value:"user_workspace_admin_role_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
name | details.group.name |
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "1234",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:32:22.377",
"details": {
"group": {
"gid": "1234",
"name": "Workspace Name",
"resource_type": "workspace"
},
"new_value": "domain_admin",
"old_value": "member"
},
"event_category": "roles",
"event_type": "user_workspace_admin_role_changed",
"gid": "1234",
"p_log_type": "Asana.Audit",
"resource": {
"email": "target@example.io",
"gid": "1234",
"name": "Bart Simpson",
"resource_type": "user"
}
}
Asana Workspace Org Export
#An Asana user started an org export.
Detection logic
def rule(event):
return event.get("event_type", "<NO_EVENT_TYPE_FOUND>") == "workspace_export_started"
def title(event):
actor_email = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
context_type = event.deep_get("context", "context_type", default="<CONTEXT_TYPE_NOT_FOUND>")
return f"Asana user [{actor_email}] started a [{context_type}] export for your organization."
Rule specification
AnalysisType: rule
Description: An Asana user started an org export.
DisplayName: Asana Workspace Org Export
Enabled: true
Filename: asana_workspace_org_export.py
Runbook: Confirm this user acted with valid business intent and determine whether this activity was authorized.
Reference: https://help.asana.com/hc/en-us/articles/14139896860955-Privacy-and-security#:~:text=like%20to%20see.-,Full%20export%20of%20an%20organization,-Available%20on%20Asana
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Org.Export"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when the condition below holds.
Condition
event_typeisworkspace_export_started
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event_type | eq |
| field:"event_type" kind:eq value:"workspace_export_started" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
context_type | context.context_type |
Response runbook
Confirm this user acted with valid business intent and determine whether this activity was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer@example.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:26:08.434",
"details": {},
"event_category": "content_export",
"event_type": "workspace_export_started",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Example IO",
"resource_type": "workspace"
}
}
Asana Workspace Password Requirements Simple
#An asana user made your organization's password requirements less strict.
Detection logic
def rule(event):
new_val = event.deep_get("details", "new_value", default="<NEW_VAL_NOT_FOUND>")
return all(
[
event.get("event_type", "<NO_EVENT_TYPE_FOUND>")
== "workspace_password_requirements_changed",
new_val == "simple",
]
)
def title(event):
actor_email = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
new_value = event.deep_get("details", "new_value", default="<NEW_VAL_NOT_FOUND>")
old_value = event.deep_get("details", "old_value", default="<OLD_VAL_NOT_FOUND>")
return (
f"Asana user [{actor_email}] changed your organization's password requirements "
f"from [{old_value}] to [{new_value}]."
)
Rule specification
AnalysisType: rule
Description: An asana user made your organization's password requirements less strict.
DisplayName: "Asana Workspace Password Requirements Simple"
Enabled: true
Filename: asana_workspace_password_requirements_simple.py
Runbook: Confirm this user acted with valid business intent and determine whether this activity was authorized.
Reference: https://help.asana.com/hc/en-us/articles/14075208738587-Authentication-and-access-management-options-for-paid-plans
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Password.Requirements.Simple"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisworkspace_password_requirements_changeddetails.new_valueissimple
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"simple" |
event_type | eq |
| field:"event_type" kind:eq value:"workspace_password_requirements_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
old_value | details.old_value |
new_value | details.new_value |
Response runbook
Confirm this user acted with valid business intent and determine whether this activity was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "12345",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:31:03.667",
"details": {
"new_value": "simple",
"old_value": "strong"
},
"event_category": "admin_settings",
"event_type": "workspace_password_requirements_changed",
"gid": "12345",
"resource": {
"gid": "12345",
"name": "Company Example IO",
"resource_type": "workspace"
}
}
Asana Workspace Require App Approvals Disabled
#An Asana user turned off app approval requirements for an application type for your organization.
Detection logic
def rule(event):
new_val = event.deep_get("details", "new_value", default="<NEW_VAL_NOT_FOUND>")
return all(
[
event.get("event_type", "<NO_EVENT_TYPE_FOUND>")
== "workspace_require_app_approvals_of_type_changed",
new_val == "off",
]
)
def title(event):
actor_email = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
context = event.deep_get("context", "context_type", default="<APP_CONTEXT_NOT_FOUND>")
return (
f"Asana user [{actor_email}] disabled application approval requirements "
f"for [{context}] type applications."
)
Rule specification
AnalysisType: rule
Description: An Asana user turned off app approval requirements for an application type for your organization.
DisplayName: Asana Workspace Require App Approvals Disabled
Enabled: true
Filename: asana_workspace_require_app_approvals_disabled.py
Runbook: Confirm this user acted with valid business intent and determine whether this activity was authorized.
Reference: https://help.asana.com/hc/en-us/articles/14109494654875-Admin-console#:~:text=used%20by%20default-,Require%20app%20approval,-Admins%20manage%20a
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.Require.App.Approvals.Disabled"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisworkspace_require_app_approvals_of_type_changeddetails.new_valueisoff
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"off" |
event_type | eq |
| field:"event_type" kind:eq value:"workspace_require_app_approvals_of_type_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
context_type | context.context_type |
Response runbook
Confirm this user acted with valid business intent and determine whether this activity was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "1234",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:29:34.968",
"details": {
"new_value": "off",
"old_value": "all_apps"
},
"event_category": "admin_settings",
"event_type": "workspace_require_app_approvals_of_type_changed",
"gid": "1234",
"resource": {
"gid": "1234",
"name": "Panther Labs",
"resource_type": "workspace"
}
}
Asana Workspace SAML Optional
#An Asana user made SAML optional for your organization.
Detection logic
def rule(event):
old_val = event.deep_get("details", "old_value", default="<OLD_VAL_NOT_FOUND>")
new_val = event.deep_get("details", "new_value", default="<NEW_VAL_NOT_FOUND>")
return all(
[
event.get("event_type", "<NO_EVENT_TYPE_FOUND>") == "workspace_saml_settings_changed",
old_val == "required",
new_val == "optional",
]
)
def title(event):
actor_email = event.deep_get("actor", "email", default="<ACTOR_NOT_FOUND>")
return f"Asana user [{actor_email}] made SAML optional for your organization."
Rule specification
AnalysisType: rule
Description: An Asana user made SAML optional for your organization.
DisplayName: "Asana Workspace SAML Optional"
Enabled: true
Filename: asana_workspace_saml_optional.py
Runbook: Confirm this user acted with valid business intent and determine whether this activity was authorized.
Reference: https://help.asana.com/hc/en-us/articles/14075208738587-Premium-Business-and-Enterprise-authentication#gl-saml:~:text=to%20your%20organization.-,SAML,-If%20your%20company
Severity: Medium
DedupPeriodMinutes: 60
LogTypes:
- Asana.Audit
RuleID: "Asana.Workspace.SAML.Optional"
Threshold: 1
Stages and Predicates
Fires on Asana.Audit events when all of the conditions below hold.
Condition
event_typeisworkspace_saml_settings_changeddetails.old_valueisrequireddetails.new_valueisoptional
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
details.new_value | eq |
| field:"details.new_value" kind:eq value:"optional" |
details.old_value | eq |
| field:"details.old_value" kind:eq value:"required" |
event_type | eq |
| field:"event_type" kind:eq value:"workspace_saml_settings_changed" |
Output fields
Fields the rule emits when it matches, drawn from the rule's alert_context.
| Field | Source |
|---|---|
email | actor.email |
Response runbook
Confirm this user acted with valid business intent and determine whether this activity was authorized.
Worked example
A sample event from the rule's unit tests that triggers a match.Sample Test Event
{
"actor": {
"actor_type": "user",
"email": "homer.simpson@example.io",
"gid": "1234",
"name": "Homer Simpson"
},
"context": {
"client_ip_address": "12.12.12.12",
"context_type": "web",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
},
"created_at": "2022-12-16 19:31:36.289",
"details": {
"new_value": "optional",
"old_value": "required"
},
"event_category": "admin_settings",
"event_type": "workspace_saml_settings_changed",
"gid": "1234",
"resource": {
"gid": "1234",
"name": "example.io",
"resource_type": "email_domain"
}
}