Detection rules › Elastic

Elastic Defend Alert from GenAI Utility or Descendant

Status
production
Severity
critical
Time window
9m
Author
Elastic
Source
github.com/elastic/detection-rules

Detects Elastic Defend alerts (behavior, malicious file, memory signature, shellcode) where the alerted process or its direct parent is a GenAI coding or assistant utility (e.g. Cursor, Claude, Windsurf, Cody, Continue, Aider, OpenClaw, Moltbot, Clawdbot, Codeium, Tabnine, GitHub Copilot). Activity from these tools can indicate prompt injection, malicious skills, or supply-chain abuse; this Higher-Order rule helps prioritize such alerts for triage.

MITRE ATT&CK coverage

Rule body elastic

[metadata]
creation_date = "2026/02/27"
maturity = "production"
min_stack_comments = "ES|QL inline stats became generally available in 9.3.0 and MV_INTERSECTION is in preview since 9.3."
min_stack_version = "9.3.0"
updated_date = "2026/04/10"

[rule]
author = ["Elastic"]
description = """
Detects Elastic Defend alerts (behavior, malicious file, memory signature, shellcode) where the alerted process or its
direct parent is a GenAI coding or assistant utility (e.g. Cursor, Claude, Windsurf, Cody, Continue, Aider, OpenClaw,
Moltbot, Clawdbot, Codeium, Tabnine, GitHub Copilot). Activity from these tools can indicate prompt injection,
malicious skills, or supply-chain abuse; this Higher-Order rule helps prioritize such alerts for triage.
"""
from = "now-9m"
interval = "5m"
language = "esql"
license = "Elastic License v2"
name = "Elastic Defend Alert from GenAI Utility or Descendant"
note = """## Triage and analysis

### Investigating Elastic Defend Alert from GenAI Utility or Descendant

Elastic Defend has raised an alert on a process that is either a GenAI coding/assistant application or a direct child of one. This can indicate prompt injection, malicious extension/skill execution, or abuse of AI-assisted development tools (e.g. fake VS Code extensions, malicious ClawHub skills).

### Possible investigation steps

- Identify the GenAI utility by looking for a process with an entity_id in Esql.genai_ancestor_ids
- Review the alert rule name and message to understand what behavior was detected (e.g. script execution, network, file write).
- Inspect process_command_line and parent command lines for download-and-execute, encoded commands, or suspicious arguments.
- Correlate with the same host and user for other alerts or with network/DNS for C2 or exfiltration.
- If the tool is Cursor/VS Code: check for recently installed extensions.
- If OpenClaw/Moltbot/Clawdbot: review installed skills and conversation history for prompt injection or malicious skill execution.

### False positive analysis

- Legitimate use of GenAI tools (e.g. running builds, package installs, or approved scripts) can trigger behavior rules. Tune by excluding known-safe rule names or process command-line patterns, or limit to higher-severity alerts.
- Approved automation or CI that runs under a GenAI-related process may need to be allowlisted.

### Response and remediation

- If abuse is confirmed: disable or restrict the GenAI tool, remove malicious extensions/skills, rotate any exposed API keys or credentials, and block IOCs at network/EDR level.
"""
references = [
    "https://attack.mitre.org/techniques/T1059/",
    "https://attack.mitre.org/techniques/T1195/002/",
]
risk_score = 99
rule_id = "d4e5f6a7-b8c9-7d0e-1f2a-3b4c5d6e7f8a"
severity = "critical"
tags = [
    "Domain: Endpoint",
    "Domain: LLM",
    "Use Case: Threat Detection",
	"Tactic: Initial Access",
    "Rule Type: Higher-Order Rule",
    "Resources: Investigation Guide",
    "Data Source: Elastic Defend",
]
timestamp_override = "event.ingested"
type = "esql"

query = '''
FROM logs-endpoint.alerts-*, logs-endpoint.events.process-* metadata _id, _version, _index 
| EVAL is_genai_spawn =  TO_LOWER(process.parent.name) IN (
        "claude", "claude.exe", "cursor", "cursor.exe", "cursor helper", "cursor helper (plugin)",
        "codex", "codex.exe", "cody", "cody.exe", "copilot", "copilot.exe", "gemini-cli", "gemini-cli.exe",
        "openai", "openai.exe", "ollama", "ollama.exe", "llm", "llm.exe",
        "aider", "aider.exe", "cline", "cline.exe", "continue", "continue.exe",
        "zed", "zed.exe", "windsurf", "windsurf.exe",
        "tabnine", "tabnine.exe", "codeium", "codeium.exe", "bolt", "bolt.exe",
        "devin", "devin.exe", "replit", "replit.exe", "ghostwriter", "ghostwriter.exe", "bito", "bito.exe"
    ),
     is_openclaw_spawn = process.parent.name in ("node", "node.exe") and (process.parent.command_line like "*openclaw*" or process.parent.command_line like "*moltbot*" or process.parent.command_line like "*clawdbot*")
| WHERE process.Ext.ancestry IS NOT NULL and 
   (data_stream.dataset == "endpoint.alerts" or is_genai_spawn or is_openclaw_spawn)
// Identify GenAI tool spawn events and capture their entity_ids
| EVAL genai_entity_id = CASE(is_genai_spawn or is_openclaw_spawn, process.parent.entity_id, NULL)

// Collect ALL GenAI entity_ids globally across the dataset
| INLINE STATS 
    all_genai_entity_ids = VALUES(genai_entity_id) WHERE genai_entity_id IS NOT NULL
// Find which GenAI entity_ids appear in this process's ancestry
| EVAL Esql.genai_ancestor_ids = MV_INTERSECTION(all_genai_entity_ids, process.Ext.ancestry)

// Elastic Defend alerts from a GenAI grandparent 
| WHERE Esql.genai_ancestor_ids IS NOT NULL 
        AND data_stream.dataset == "endpoint.alerts" AND not rule.name in (
            "Persistence via GenAI Tool",
            "Code Editor Untrusted or Unsigned Child Process Execution",
            "Suspicious Credential Access via GenAI Tool",
            "Credential Access via GenAI Tool Descendant"
        )

| KEEP *
'''

[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1195"
name = "Supply Chain Compromise"
reference = "https://attack.mitre.org/techniques/T1195/"
[[rule.threat.technique.subtechnique]]
id = "T1195.002"
name = "Compromise Software Supply Chain"
reference = "https://attack.mitre.org/techniques/T1195/002/"

[rule.threat.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"

Stages and Predicates

Stage 1: from

FROM logs-endpoint.alerts-*, logs-endpoint.events.process-* metadata _id, _version, _index

Stage 2: eval

| EVAL is_genai_spawn =  TO_LOWER(process.parent.name) IN (
        "claude", "claude.exe", "cursor", "cursor.exe", "cursor helper", "cursor helper (plugin)",
        "codex", "codex.exe", "cody", "cody.exe", "copilot", "copilot.exe", "gemini-cli", "gemini-cli.exe",
        "openai", "openai.exe", "ollama", "ollama.exe", "llm", "llm.exe",
        "aider", "aider.exe", "cline", "cline.exe", "continue", "continue.exe",
        "zed", "zed.exe", "windsurf", "windsurf.exe",
        "tabnine", "tabnine.exe", "codeium", "codeium.exe", "bolt", "bolt.exe",
        "devin", "devin.exe", "replit", "replit.exe", "ghostwriter", "ghostwriter.exe", "bito", "bito.exe"
    ),
     is_openclaw_spawn = process.parent.name in ("node", "node.exe") and (process.parent.command_line like "*openclaw*" or process.parent.command_line like "*moltbot*" or process.parent.command_line like "*clawdbot*")

Stage 3: where

| WHERE process.Ext.ancestry IS NOT NULL and
   (data_stream.dataset == "endpoint.alerts" or is_genai_spawn or is_openclaw_spawn)

Stage 4: eval

| EVAL genai_entity_id = CASE(is_genai_spawn or is_openclaw_spawn, process.parent.entity_id, NULL)
genai_entity_id =
ifis_genai_spawn or is_openclaw_spawnprocess.parent.entity_id
elseNULL

Stage 5: inline_stats

| INLINE STATS
    all_genai_entity_ids = VALUES(genai_entity_id) WHERE genai_entity_id IS NOT NULL

Stage 6: eval

| EVAL Esql.genai_ancestor_ids = MV_INTERSECTION(all_genai_entity_ids, process.Ext.ancestry)

Stage 7: where

| WHERE Esql.genai_ancestor_ids IS NOT NULL 
        AND data_stream.dataset == "endpoint.alerts" AND not rule.name in (
            "Persistence via GenAI Tool",
            "Code Editor Untrusted or Unsigned Child Process Execution",
            "Suspicious Credential Access via GenAI Tool",
            "Credential Access via GenAI Tool Descendant"
        )

Stage 8: keep

| KEEP *

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
rule.nameinCode Editor Untrusted or Unsigned Child Process Execution, Credential Access via GenAI Tool Descendant, Persistence via GenAI Tool, Suspicious Credential Access via GenAI Tool

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
Esql.genai_ancestor_idsis_not_null
  • (no value, null check)
data_stream.dataseteq
  • endpoint.alerts corpus 6 (elastic 6)
process.Ext.ancestryis_not_null
  • (no value, null check)

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
*KEEP *