{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "keep-as-periodic-hunt",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "Agent User identities are trusted internal accounts that bypass standard interactive MFA; their use for Teams-based phishing represents a high-trust lateral movement risk."
      },
      "name": "Entra ID Agent User Impersonation and Teams Abuse",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1059.001"
      ],
      "related": [
        {
          "hunt": "suspicious-microsoft-graph-api-activity",
          "reason": "This hunt focuses on the Agent User OAuth flow, whereas the sibling hunt covers general Graph API abuse.",
          "relation": "sibling"
        }
      ],
      "targets": {
        "web": {
          "name": "Web server / proxy logs",
          "category": "siem",
          "telemetry": [
            "network"
          ]
        },
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        },
        "identity": {
          "name": "Identity / sign-in telemetry",
          "category": "identity",
          "telemetry": [
            "identity"
          ]
        }
      },
      "analysis": "This hunt uses three distinct surfaces\u2014Entra sign-ins, host-based PowerShell script blocks, and HTTP gateway telemetry\u2014to identify a specific impersonation flow that a single log source cannot fully contextualize. It specifically uses prevalence counting to find rare User-Agents and scripts that standard rules would miss.",
      "coverage": [
        {
          "stage": "agent-user-oauth-authentication",
          "steps": [
            "identify-agent-user-logons"
          ],
          "status": "covered"
        },
        {
          "stage": "graph-api-teams-message-dispatch",
          "steps": [
            "rare-graph-beta-scripts",
            "graph-api-user-agents"
          ],
          "status": "covered"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "Agent User OAuth Flow Authentication",
            "slug": "agent-user-oauth-authentication",
            "tactic": "execution",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "login.microsoftonline.com",
              "api://AzureADTokenExchange/.default",
              "grant_type=user_fic",
              "requested_token_use=on_behalf_of",
              "user_federated_identity_credential",
              "agent.agentSubjectType == agentIDuser",
              "agent.agentType == agenticAppInstance"
            ]
          },
          {
            "name": "Teams Message Dispatch via Graph API",
            "slug": "graph-api-teams-message-dispatch",
            "tactic": "initial-access",
            "techniques": [
              "T1059.001"
            ],
            "observables": [
              "microsoft.graph.beta",
              "Mozilla/5.0 (Macintosh; macOS 26.4.1; en-US) PowerShell/7.6.1",
              "51.3.97.221",
              "70.152.145.147",
              "New-MgBetaTeamChannelMessage",
              "https://domoarigato.ai/",
              "domoarigato.ai"
            ]
          }
        ],
        "summary": "An attacker abuses Microsoft Entra ID Agent User identities to distribute malicious links via Microsoft Teams. The attack involves executing a PowerShell script on a macOS host to perform a specialized OAuth flow, impersonating an agent user to call the Graph API and send messages to team channels."
      },
      "severity": "high",
      "rationale": "Focus on identities using the 'user_fic' grant type; this is the primary indicator of the Agent User OAuth flow. Start with cloud sign-in logs to establish a list of active Agent Users before pivoting to endpoint script activity.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An attacker uses the Entra ID Agent User OAuth flow to impersonate an AI agent and dispatch malicious content via Microsoft Teams using Graph API cmdlets.",
      "parameters": {
        "scope_hosts": {
          "type": "list[host]",
          "default": [],
          "description": "Optional list of hosts to narrow behavioral queries."
        },
        "lookback_days": {
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://redcanary.com/blog/threat-detection/entra-id-ai-workflows-teams/",
          "gates": [
            "dry-run",
            "lint"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://redcanary.com/blog/threat-detection/entra-id-ai-workflows-teams/",
          "name": "Red Canary \u2014 Investigating suspicious AI workflows in Microsoft Entra Agent ID"
        }
      ],
      "blind_spots": [
        {
          "id": "no-graph-visibility",
          "risk": "If the proxy does not decrypt Graph traffic, the User-Agent is invisible, forcing reliance on endpoint script logs.",
          "stage": "graph-api-teams-message-dispatch",
          "question": "Can we see the User-Agent in Graph API requests?",
          "requires": "hb_http_activity with TLS decryption"
        },
        {
          "id": "script-block-logging-disabled",
          "risk": "If script block logging is disabled, the specific commands used to dispatch messages cannot be recovered from hb_script_activity.",
          "stage": "graph-api-teams-message-dispatch",
          "question": "Can we see the content of the mgbeta cmdlets?",
          "requires": "PowerShell Script Block Logging (EID 4104)"
        }
      ]
    },
    "name": "Entra ID Agent User Impersonation and Teams Abuse",
    "description": "This hunt identifies unauthorized use of Entra ID Agent User identities by correlating non-interactive authentication patterns with endpoint PowerShell script execution. It targets the 'user_fic' grant type and the impersonation of identities with an 'agentIDuser' subject type. The hunt flows from cloud authentication logs to endpoint telemetry, looking for specific Graph Beta PowerShell cmdlets and rare User-Agent strings used to send messages to Teams channels. An agent evaluates the combined evidence to distinguish legitimate autonomous agent activity from manual attacker-driven impersonation, specifically checking for temporal proximity between the cloud logon and the execution of script blocks."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "coverage": [
          {
            "stage": "agent-user-oauth-authentication",
            "steps": [
              "identify-agent-user-logons"
            ],
            "status": "covered"
          },
          {
            "stage": "graph-api-teams-message-dispatch",
            "steps": [
              "rare-graph-beta-scripts",
              "graph-api-user-agents"
            ],
            "status": "covered"
          }
        ],
        "rationale": "An attacker uses the Entra ID Agent User OAuth flow to impersonate an AI agent and dispatch malicious content via Microsoft Teams using Graph API cmdlets.",
        "blind_spots": [
          {
            "id": "no-graph-visibility",
            "risk": "If the proxy does not decrypt Graph traffic, the User-Agent is invisible, forcing reliance on endpoint script logs.",
            "stage": "graph-api-teams-message-dispatch",
            "question": "Can we see the User-Agent in Graph API requests?",
            "requires": "hb_http_activity with TLS decryption"
          },
          {
            "id": "script-block-logging-disabled",
            "risk": "If script block logging is disabled, the specific commands used to dispatch messages cannot be recovered from hb_script_activity.",
            "stage": "graph-api-teams-message-dispatch",
            "question": "Can we see the content of the mgbeta cmdlets?",
            "requires": "PowerShell Script Block Logging (EID 4104)"
          }
        ],
        "scoping_notes": "Focus on identities using the 'user_fic' grant type; this is the primary indicator of the Agent User OAuth flow. Start with cloud sign-in logs to establish a list of active Agent Users before pivoting to endpoint script activity.",
        "beyond_detection": "This hunt uses three distinct surfaces\u2014Entra sign-ins, host-based PowerShell script blocks, and HTTP gateway telemetry\u2014to identify a specific impersonation flow that a single log source cannot fully contextualize. It specifically uses prevalence counting to find rare User-Agents and scripts that standard rules would miss."
      }
    },
    {
      "id": "identify-agent-user-logons",
      "type": "query",
      "label": "Identify Agent User OAuth logons",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "identity",
        "content": "SELECT actor_user_name, src_endpoint_ip, auth_protocol, dst_endpoint_name, time FROM hb_auth_signin WHERE provider = 'm365' AND LOWER(dst_endpoint_name) = 'microsoft teams' AND (LOWER(auth_protocol) LIKE '%user_fic%' OR LOWER(actor_user_name) LIKE '%agent%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_auth_signin",
        "description": "Find non-interactive sign-ins to Microsoft Teams that use the federated identity credentials specific to Agent User impersonation.",
        "expected_signal": "Rows showing identities authenticating to Teams via the Agent User flow (user_fic). Silence suggests no such identities are active in the window."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Identify Agent User OAuth logons",
        "reads": [
          "actor_user_name",
          "src_endpoint_ip",
          "auth_protocol",
          "dst_endpoint_name",
          "time"
        ],
        "source": "hb_auth_signin",
        "target": "identity",
        "content": "SELECT actor_user_name, src_endpoint_ip, auth_protocol, dst_endpoint_name, time FROM hb_auth_signin WHERE provider = 'm365' AND LOWER(dst_endpoint_name) = 'microsoft teams' AND (LOWER(auth_protocol) LIKE '%user_fic%' OR LOWER(actor_user_name) LIKE '%agent%') AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Rows showing identities authenticating to Teams via the Agent User flow (user_fic). Silence suggests no such identities are active in the window.",
        "verified": "dry-run",
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "rare-graph-beta-scripts",
      "type": "query",
      "label": "Rare Graph Beta PowerShell scripts",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "endpoint",
        "content": "SELECT script_content, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_script_activity WHERE (LOWER(script_content) LIKE '%new-mgbetateamchannelmessage%' OR LOWER(script_content) LIKE '%connect-mggraph%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY script_content HAVING hosts < 5",
        "surface": "hb_script_activity",
        "description": "Identify rare script blocks that call the specific Beta cmdlets used for Teams messaging to find manual dispatch activity.",
        "expected_signal": "Rare script blocks containing the Teams dispatch cmdlets. Common automation scripts will be filtered out by the prevalence count."
      },
      "parents": [
        {
          "id": "identify-agent-user-logons"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Rare Graph Beta PowerShell scripts",
        "reads": [
          "device_hostname",
          "script_content",
          "time"
        ],
        "source": "hb_script_activity",
        "target": "endpoint",
        "content": "SELECT script_content, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_script_activity WHERE (LOWER(script_content) LIKE '%new-mgbetateamchannelmessage%' OR LOWER(script_content) LIKE '%connect-mggraph%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY script_content HAVING hosts < 5",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "Rare script blocks containing the Teams dispatch cmdlets. Common automation scripts will be filtered out by the prevalence count.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "script_content"
          ],
          "rare_below": 5
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "graph-api-user-agents",
      "type": "query",
      "label": "Rare Graph API User-Agents",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "web",
        "content": "SELECT user_agent, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_http_activity WHERE url_hostname LIKE '%graph.microsoft.com%' AND user_agent LIKE '%PowerShell/%' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY user_agent HAVING hosts < 5",
        "surface": "hb_http_activity",
        "description": "Identify rare User-Agents hitting Microsoft Graph endpoints to isolate attacker-controlled PowerShell sessions.",
        "expected_signal": "A User-Agent string hitting Graph that is not part of the standard fleet automation baseline."
      },
      "parents": [
        {
          "id": "identify-agent-user-logons"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "Rare Graph API User-Agents",
        "reads": [
          "device_hostname",
          "url_hostname",
          "user_agent",
          "time"
        ],
        "source": "hb_http_activity",
        "target": "web",
        "content": "SELECT user_agent, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_http_activity WHERE url_hostname LIKE '%graph.microsoft.com%' AND user_agent LIKE '%PowerShell/%' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY user_agent HAVING hosts < 5",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "A User-Agent string hitting Graph that is not part of the standard fleet automation baseline.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "user_agent"
          ],
          "rare_below": 5
        },
        "verified_at": "2026-09-20"
      }
    },
    {
      "id": "triage-impersonation",
      "type": "analytic",
      "label": "Triage agent impersonation",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "identity",
          "web"
        ],
        "context": [
          "identify-agent-user-logons",
          "rare-graph-beta-scripts",
          "graph-api-user-agents"
        ],
        "objective": "Determine if an Entra ID Agent User was used by an unauthorized process to send suspicious Teams messages. Explicitly check for temporal proximity, such as a 60-minute window, between the Agent User sign-in event and the endpoint script execution or HTTP traffic.",
        "description": "Correlate the OAuth identity flow with the specific script content and User-Agent to determine if the activity is malicious.",
        "max_iterations": 4,
        "expected_signal": "A per-host verdict citing specific scripts and sign-in events.",
        "success_criteria": "A verdict of malicious | suspicious | benign for each identity, citing the script blocks and timestamps."
      },
      "parents": [
        {
          "id": "rare-graph-beta-scripts",
          "kind": "merge"
        },
        {
          "id": "graph-api-user-agents",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "route-response",
      "type": "checkpoint",
      "label": "Route on verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "the triage verdict is malicious for at least one agent user",
        "condition": "the triage verdict is malicious for at least one agent user",
        "blind_spot": "no-graph-visibility",
        "confidence": "high",
        "description": "Direct the hunt to containment if impersonation is confirmed.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "triage-impersonation"
        }
      ]
    },
    {
      "id": "revoke-and-purge",
      "type": "action",
      "label": "Revoke sessions and purge messages",
      "config": {
        "target": "identity",
        "description": "Neutralize the compromised identity and remove malicious content from Teams.",
        "instructions": "Revoke all active OAuth refresh tokens for the identified Agent User and its parent Blueprint principal in Entra ID. Use the Teams Messaging Policy or Purview to identify and delete malicious messages sent by this agent user.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "route-response",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-manual-review",
      "type": "task",
      "label": "Analyst manual review",
      "config": {
        "assignee": "analyst",
        "description": "Verify the agent's findings and confirm remediation success.",
        "instructions": "Review the cited script blocks and Graph API activity. Verify the revoked identity is no longer active and that reported messages have been successfully purged from Teams."
      },
      "parents": [
        {
          "id": "route-response",
          "branch": "default"
        },
        {
          "id": "route-response",
          "branch": "on_unavailable"
        },
        {
          "id": "revoke-and-purge"
        }
      ]
    },
    {
      "id": "close-out",
      "type": "task",
      "label": "Close out",
      "config": {
        "assignee": "analyst",
        "description": "Final documentation and reporting.",
        "instructions": "Record incident findings. If the rare PowerShell User-Agent was consistent, consider promoting the HTTP query to a permanent detection rule."
      },
      "parents": [
        {
          "id": "route-response",
          "branch": "on_refutes"
        },
        {
          "id": "analyst-manual-review"
        }
      ]
    }
  ]
}