Azure Automation Webhook Created


Description

Detects when an Azure Automation webhook is created. A webhook uses a custom URL passed to Azure Automation along with a data payload specific to the runbook. Adversaries may exploit this capability to trigger runbooks containing malicious code for persistence or to execute unauthorized actions in the environment.

Query · python

from panther_azureactivity_helpers import (
    azure_activity_alert_context,
    azure_activity_success,
    extract_resource_name_from_id,
)

AUTOMATION_WEBHOOK_OPERATIONS = [
    "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/ACTION",
    "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/WRITE",
]


def rule(event):
    return event.get(
        "operationName", ""
    ).upper() in AUTOMATION_WEBHOOK_OPERATIONS and azure_activity_success(event)


def title(event):
    resource_id = event.get("resourceId", "<UNKNOWN_RESOURCE>")

    webhook_name = extract_resource_name_from_id(
        resource_id, "webhooks", default="<UNKNOWN_WEBHOOK_NAME>"
    )

    return f"Azure Automation Webhook Created: [{webhook_name}]"


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

    resource_id = event.get("resourceId", "")

    webhook_name = extract_resource_name_from_id(resource_id, "webhooks", default="")
    if webhook_name:
        context["webhook_name"] = webhook_name

    automation_account_name = extract_resource_name_from_id(
        resource_id, "automationAccounts", default=""
    )
    if automation_account_name:
        context["automation_account_name"] = automation_account_name

    return context

Analyst notes

  1. Query Azure Monitor Activity logs for all automation account operations (account creation, runbook creation, webhook creation) by the callerIpAddress in the 24 hours before and after the alert to identify a sequence of persistence activities
  2. Find all webhook creations in the past 6 hours to determine if multiple persistence mechanisms are being established
  3. Check if the callerIpAddress has created webhooks in the past 90 days to determine if this is typical automation workflow deployment
Raw source Azure Automation Webhook Created · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: azure_automation_webhook_created.py
RuleID: "Azure.MonitorActivity.Automation.WebhookCreated"
DisplayName: "Azure Automation Webhook Created"
Enabled: true
LogTypes:
  - Azure.MonitorActivity
Severity: Info
Description: >
  Detects when an Azure Automation webhook is created. A webhook uses a custom URL passed to
  Azure Automation along with a data payload specific to the runbook. Adversaries may exploit
  this capability to trigger runbooks containing malicious code for persistence or to execute
  unauthorized actions in the environment.
Reports:
  MITRE ATT&CK:
    - TA0003:T1546 # Persistence: Event Triggered Execution
    - TA0042:T1608 # Resource Development: Stage Capabilities
Tags:
- AZT502
- AZT503
- AZT503.3
- Persistence
- Resource Development
- Event Triggered Execution
- Stage Capabilities
Runbook: |
  1. Query Azure Monitor Activity logs for all automation account operations (account creation, runbook creation, webhook creation) by the callerIpAddress in the 24 hours before and after the alert to identify a sequence of persistence activities
  2. Find all webhook creations in the past 6 hours to determine if multiple persistence mechanisms are being established
  3. Check if the callerIpAddress has created webhooks in the past 90 days to determine if this is typical automation workflow deployment
Reference: https://github.com/elastic/detection-rules/blob/main/rules/integrations/azure/persistence_automation_webhook_created.toml
SummaryAttributes:
  - resourceId
  - callerIpAddress
  - correlationId
Tests:
  - Name: Automation Webhook Created with ACTION
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-22T10:30:00.0000000Z",
        "resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/automation-rg/providers/Microsoft.Automation/automationAccounts/my-automation/webhooks/malicious-webhook",
        "operationName": "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/ACTION",
        "operationVersion": "2021-06-22",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "1.1.1.1",
        "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "level": "Informational",
        "location": "eastus",
        "tenantId": "87654321-4321-4321-4321-111111111111"
      }
  - Name: Automation Webhook Created with WRITE
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-22T11:15:00.0000000Z",
        "resourceId": "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/prod-automation/providers/Microsoft.Automation/automationAccounts/prod-automation/webhooks/prod-webhook",
        "operationName": "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/WRITE",
        "category": "Administrative",
        "resultType": "Succeeded",
        "callerIpAddress": "2.2.2.2",
        "correlationId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
        "level": "Information",
        "location": "westeurope",
        "tenantId": "22222222-2222-2222-2222-222222222222"
      }
  - Name: Case Insensitive Match
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-22T12:00:00.0000000Z",
        "resourceId": "/subscriptions/33333333-3333-3333-3333-333333333333/resourceGroups/test-rg/providers/Microsoft.Automation/automationAccounts/test-account/webhooks/test-webhook",
        "operationName": "microsoft.automation/automationaccounts/webhooks/action",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "3.3.3.3",
        "correlationId": "c3d4e5f6-a7b8-9012-cdef-333333333333",
        "location": "centralus",
        "tenantId": "33333333-3333-3333-3333-333333333333"
      }
  - Name: Different Operation
    ExpectedResult: false
    Log:
      {
        "time": "2025-12-22T14:00:00.0000000Z",
        "resourceId": "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/automation-rg/providers/Microsoft.Automation/automationAccounts/my-automation/webhooks/old-webhook",
        "operationName": "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/DELETE",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "5.5.5.5",
        "correlationId": "e5f6a7b8-c9d0-1234-ef01-567890123456",
        "location": "southcentralus",
        "tenantId": "55555555-5555-5555-5555-555555555555"
      }

# ------ paired body: azure_automation_webhook_created.py ------

from panther_azureactivity_helpers import (
    azure_activity_alert_context,
    azure_activity_success,
    extract_resource_name_from_id,
)

AUTOMATION_WEBHOOK_OPERATIONS = [
    "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/ACTION",
    "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/WRITE",
]


def rule(event):
    return event.get(
        "operationName", ""
    ).upper() in AUTOMATION_WEBHOOK_OPERATIONS and azure_activity_success(event)


def title(event):
    resource_id = event.get("resourceId", "<UNKNOWN_RESOURCE>")

    webhook_name = extract_resource_name_from_id(
        resource_id, "webhooks", default="<UNKNOWN_WEBHOOK_NAME>"
    )

    return f"Azure Automation Webhook Created: [{webhook_name}]"


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

    resource_id = event.get("resourceId", "")

    webhook_name = extract_resource_name_from_id(resource_id, "webhooks", default="")
    if webhook_name:
        context["webhook_name"] = webhook_name

    automation_account_name = extract_resource_name_from_id(
        resource_id, "automationAccounts", default=""
    )
    if automation_account_name:
        context["automation_account_name"] = automation_account_name

    return context

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.