Suspicious Command Execution from Visual Studio Code

Detects Visual Studio Code ("Code.exe" on Windows or "Code Helper" on macOS) spawning a shell or downloader whose command line contains an encoded command, a download cradle, or a reverse-shell pattern. Malicious IDE extensions use the editor process to run these commands after install.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/10/26"
  3integration = ["endpoint"]
  4maturity = "production"
  5updated_date = "2026/10/26"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects Visual Studio Code ("Code.exe" on Windows or "Code Helper" on macOS) spawning a shell or downloader whose
 11command line contains an encoded command, a download cradle, or a reverse-shell pattern. Malicious IDE extensions
 12use the editor process to run these commands after install.
 13"""
 14from = "now-9m"
 15language = "esql"
 16license = "Elastic License v2"
 17name = "Suspicious Command Execution from Visual Studio Code"
 18note = """## Triage and analysis
 19
 20### Investigating Suspicious Command Execution from Visual Studio Code
 21
 22`Code.exe` or `Code Helper` started `cmd`, PowerShell, a Unix shell, `curl`, or `wget`, and the command line matches
 23an encoded-command, download, or remote-shell pattern. That is common when a malicious VS Code extension, task, or
 24workspace script runs through the editor.
 25
 26### Possible investigation steps
 27
 28- Review `process.command_line` for the URL, encoded payload, or shell pipe (`curl | sh`, `wget | sh`, `Invoke-Expression`).
 29- Review `process.parent.command_line` and `process.parent.args` for `extensionHost` or a path under `.vscode/extensions` or `.vscode/tasks.json`.
 30- Identify the extension id from that parent path and compare it with the installed extension.
 31- On the same host and user, look for the downloaded file, follow-on processes, and outbound connections.
 32
 33### False positive analysis
 34
 35- Developer tasks and integrated terminals often run `curl`, `wget`, `echo`, or `https` URLs. `echo` and `https` in the
 36  pattern match many legitimate commands. Confirm the parent is an extension host or an unexpected workspace task before excluding.
 37- The rule already excludes command lines containing `docker.internal`, `localhost`, `127.0.0.1`, or `aka.ms/vscode-powershell`.
 38- Scope exceptions to a known command line, extension path, host, or user. Do not broadly exclude `Code.exe` or `Code Helper`.
 39
 40### Response and remediation
 41
 42- If the command is unapproved, stop the child process, uninstall the extension, and remove any dropped file.
 43- Quarantine the payload, collect its hash, and hunt the command line on other hosts.
 44- Rotate tokens or credentials the command could have read from the user profile or workspace.
 45"""
 46references = [
 47    "https://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/",
 48    "https://www.aikido.dev/blog/fake-clawdbot-vscode-extension-malware",
 49]
 50risk_score = 47
 51rule_id = "cb602a92-6613-4425-b983-61fcb02b647c"
 52setup = """## Setup
 53
 54This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
 55
 56Setup instructions: https://ela.st/install-elastic-defend
 57"""
 58severity = "medium"
 59tags = [
 60    "Domain: Endpoint",
 61    "OS: Windows",
 62    "OS: macOS",
 63    "OS: Linux",
 64    "Use Case: Threat Detection",
 65    "Tactic: Persistence",
 66    "Tactic: Execution",
 67    "Data Source: Elastic Defend",
 68    "Resources: Investigation Guide",
 69    "Rule Type: ES|QL",
 70    "Platform: Windows",
 71    "Platform: macOS",
 72    "Platform: Linux"
 73]
 74timestamp_override = "event.ingested"
 75type = "esql"
 76
 77query = '''
 78FROM logs-endpoint.events.process-* METADATA _id, _version, _index
 79| WHERE KQL("""event.category:process and event.type:start""")
 80  AND process.parent.name IN ("Code Helper (Plugin)", "Code Helper", "Code.exe", "code")
 81  AND process.name IN (
 82    "cmd.exe", "powershell.exe", "sh", "bash", "zsh",
 83    "dash", "nohup", "curl.exe", "curl", "wget",
 84    "wget.exe", "pwsh.exe"
 85  )
 86  AND TO_LOWER(process.command_line) RLIKE """.*(-ec |-enc|-encodedcommand|-nop |-w hidden|https|/dev/tcp|echo|irm |iwr |base64|nohup|http:|iex |invoke-expression|downloadstring|downloadfile|frombase64string|chmod \+|nc -e|ncat|certutil|bitsadmin|invoke-restmethod|curl.*\|.*sh|wget.*\|.*sh).*"""
 87  AND NOT TO_LOWER(process.command_line) RLIKE """.*(docker.internal|localhost|127.0.0.1|aka.ms/vscode-powershell).*"""
 88| KEEP
 89    _id,
 90    _version,
 91    _index,
 92    data_stream.namespace,
 93    @timestamp,
 94    host.name,
 95    host.id,
 96    agent.id,
 97    host.os.type,
 98    user.name,
 99    user.domain,
100    process.name,
101    process.parent.name,
102    process.parent.executable,
103    process.command_line,
104    process.executable,
105    process.parent.command_line,
106    process.parent.args
107'''
108
109[rule.investigation_fields]
110field_names = [
111    "host.os.type",
112    "process.parent.name",
113    "process.parent.executable",
114    "process.parent.command_line",
115    "process.parent.args",
116    "process.command_line",
117    "process.executable",
118]
119
120[[rule.threat]]
121framework = "MITRE ATT&CK"
122
123[[rule.threat.technique]]
124id = "T1176"
125name = "Software Extensions"
126reference = "https://attack.mitre.org/techniques/T1176/"
127
128[[rule.threat.technique.subtechnique]]
129id = "T1176.002"
130name = "IDE Extensions"
131reference = "https://attack.mitre.org/techniques/T1176/002/"
132
133[rule.threat.tactic]
134id = "TA0003"
135name = "Persistence"
136reference = "https://attack.mitre.org/tactics/TA0003/"
137
138[[rule.threat]]
139framework = "MITRE ATT&CK"
140
141[[rule.threat.technique]]
142id = "T1059"
143name = "Command and Scripting Interpreter"
144reference = "https://attack.mitre.org/techniques/T1059/"
145
146[[rule.threat.technique.subtechnique]]
147id = "T1059.001"
148name = "PowerShell"
149reference = "https://attack.mitre.org/techniques/T1059/001/"
150
151[[rule.threat.technique.subtechnique]]
152id = "T1059.003"
153name = "Windows Command Shell"
154reference = "https://attack.mitre.org/techniques/T1059/003/"
155
156[[rule.threat.technique.subtechnique]]
157id = "T1059.004"
158name = "Unix Shell"
159reference = "https://attack.mitre.org/techniques/T1059/004/"
160
161[rule.threat.tactic]
162id = "TA0002"
163name = "Execution"
164reference = "https://attack.mitre.org/tactics/TA0002/"

Triage and analysis

Investigating Suspicious Command Execution from Visual Studio Code

Code.exe or Code Helper started cmd, PowerShell, a Unix shell, curl, or wget, and the command line matches an encoded-command, download, or remote-shell pattern. That is common when a malicious VS Code extension, task, or workspace script runs through the editor.

Possible investigation steps

  • Review process.command_line for the URL, encoded payload, or shell pipe (curl | sh, wget | sh, Invoke-Expression).
  • Review process.parent.command_line and process.parent.args for extensionHost or a path under .vscode/extensions or .vscode/tasks.json.
  • Identify the extension id from that parent path and compare it with the installed extension.
  • On the same host and user, look for the downloaded file, follow-on processes, and outbound connections.

False positive analysis

  • Developer tasks and integrated terminals often run curl, wget, echo, or https URLs. echo and https in the pattern match many legitimate commands. Confirm the parent is an extension host or an unexpected workspace task before excluding.
  • The rule already excludes command lines containing docker.internal, localhost, 127.0.0.1, or aka.ms/vscode-powershell.
  • Scope exceptions to a known command line, extension path, host, or user. Do not broadly exclude Code.exe or Code Helper.

Response and remediation

  • If the command is unapproved, stop the child process, uninstall the extension, and remove any dropped file.
  • Quarantine the payload, collect its hash, and hunt the command line on other hosts.
  • Rotate tokens or credentials the command could have read from the user profile or workspace.

References

Related rules

to-top