Suspicious Command Execution from Visual Studio Code


Description

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.

Query · esql

FROM logs-endpoint.events.process-* METADATA _id, _version, _index
| WHERE KQL("""event.category:process and event.type:start""")
  AND process.parent.name IN ("Code Helper (Plugin)", "Code Helper", "Code.exe", "code")
  AND process.name IN (
    "cmd.exe", "powershell.exe", "sh", "bash", "zsh",
    "dash", "nohup", "curl.exe", "curl", "wget",
    "wget.exe", "pwsh.exe"
  )
  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).*"""
  AND NOT TO_LOWER(process.command_line) RLIKE """.*(docker.internal|localhost|127.0.0.1|aka.ms/vscode-powershell).*"""
| KEEP
    _id,
    _version,
    _index,
    data_stream.namespace,
    @timestamp,
    host.name,
    host.id,
    agent.id,
    host.os.type,
    user.name,
    user.domain,
    process.name,
    process.parent.name,
    process.parent.executable,
    process.command_line,
    process.executable,
    process.parent.command_line,
    process.parent.args

Investigation fields

Pivot points the source recommends for triage.

  • host.os.type
  • process.parent.name
  • process.parent.executable
  • process.parent.command_line
  • process.parent.args
  • process.command_line
  • process.executable

Implementation guide

This rule is designed for data generated by Elastic Defend, which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.

Setup instructions: https://ela.st/install-elastic-defend

Analyst notes

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.
Raw source Suspicious Command Execution from Visual Studio Code · Elastic TOML
Esc
Published by elastic/detection-rules ↗, licensed under Elastic License 2.0 ↗. Reproduced here unmodified.
[metadata]
creation_date = "2026/10/26"
integration = ["endpoint"]
maturity = "production"
updated_date = "2026/10/26"

[rule]
author = ["Elastic"]
description = """
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.
"""
from = "now-9m"
language = "esql"
license = "Elastic License v2"
name = "Suspicious Command Execution from Visual Studio Code"
note = """## 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 = [
    "https://www.mdsec.co.uk/2021/01/macos-post-exploitation-shenanigans-with-vscode-extensions/",
    "https://www.aikido.dev/blog/fake-clawdbot-vscode-extension-malware",
]
risk_score = 47
rule_id = "cb602a92-6613-4425-b983-61fcb02b647c"
setup = """## Setup

This 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.

Setup instructions: https://ela.st/install-elastic-defend
"""
severity = "medium"
tags = [
    "Domain: Endpoint",
    "OS: Windows",
    "OS: macOS",
    "OS: Linux",
    "Use Case: Threat Detection",
    "Tactic: Persistence",
    "Tactic: Execution",
    "Data Source: Elastic Defend",
    "Resources: Investigation Guide",
    "Rule Type: ES|QL",
    "Platform: Windows",
    "Platform: macOS",
    "Platform: Linux"
]
timestamp_override = "event.ingested"
type = "esql"

query = '''
FROM logs-endpoint.events.process-* METADATA _id, _version, _index
| WHERE KQL("""event.category:process and event.type:start""")
  AND process.parent.name IN ("Code Helper (Plugin)", "Code Helper", "Code.exe", "code")
  AND process.name IN (
    "cmd.exe", "powershell.exe", "sh", "bash", "zsh",
    "dash", "nohup", "curl.exe", "curl", "wget",
    "wget.exe", "pwsh.exe"
  )
  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).*"""
  AND NOT TO_LOWER(process.command_line) RLIKE """.*(docker.internal|localhost|127.0.0.1|aka.ms/vscode-powershell).*"""
| KEEP
    _id,
    _version,
    _index,
    data_stream.namespace,
    @timestamp,
    host.name,
    host.id,
    agent.id,
    host.os.type,
    user.name,
    user.domain,
    process.name,
    process.parent.name,
    process.parent.executable,
    process.command_line,
    process.executable,
    process.parent.command_line,
    process.parent.args
'''

[rule.investigation_fields]
field_names = [
    "host.os.type",
    "process.parent.name",
    "process.parent.executable",
    "process.parent.command_line",
    "process.parent.args",
    "process.command_line",
    "process.executable",
]

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1176"
name = "Software Extensions"
reference = "https://attack.mitre.org/techniques/T1176/"

[[rule.threat.technique.subtechnique]]
id = "T1176.002"
name = "IDE Extensions"
reference = "https://attack.mitre.org/techniques/T1176/002/"

[rule.threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"

[[rule.threat.technique.subtechnique]]
id = "T1059.001"
name = "PowerShell"
reference = "https://attack.mitre.org/techniques/T1059/001/"

[[rule.threat.technique.subtechnique]]
id = "T1059.003"
name = "Windows Command Shell"
reference = "https://attack.mitre.org/techniques/T1059/003/"

[[rule.threat.technique.subtechnique]]
id = "T1059.004"
name = "Unix Shell"
reference = "https://attack.mitre.org/techniques/T1059/004/"

[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"

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.