Detection rules › Elastic

Potential Execution via VS Code Tasks

Time window
30s
Source
github.com/elastic/protections-artifacts

Identifies creation or modification of a .vscode/tasks.json file followed by opening the current project in a short time. Threat actors distribute malicious repositories that embed autorun task configurations to phish for credentials or execute payloads when a developer opens the project in Visual Studio Code.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

[rule]
description = """
Identifies creation or modification of a .vscode/tasks.json file followed by opening the current project in a short
time. Threat actors distribute malicious repositories that embed autorun task configurations to phish for credentials or
execute payloads when a developer opens the project in Visual Studio Code.
"""
id = "ad058e28-8504-4bfe-9b91-22d24d903ede"
license = "Elastic License v2"
name = "Potential Execution via VS Code Tasks"
os_list = ["macos"]
reference = [
    "https://www.jamf.com/blog/threat-actors-expand-abuse-of-visual-studio-code/",
    "https://about.gitlab.com/blog/how-to-detect-and-prevent-contagious-interview-ide-attacks/",
    "https://kl4r10n.tech/blog/dprk-new-malware",
]
version = "1.0.2"

query = '''
sequence with maxspan=30s
  [file where event.action in ("creation", "modification") and file.name == "tasks.json" and
   process.name in (
     // Windows browsers
     "chrome.exe", "msedge.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe",
     // macOS browsers (bundle exec names)
     "Google Chrome", "Google Chrome Helper", "Chromium", "Chromium Helper",
     "firefox", "Firefox", "Safari", "SafariTP",
     "Brave Browser", "Opera", "Vivaldi", "Arc",
     // Linux browsers
     "google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
     "firefox", "firefox-esr", "brave-browser", "opera", "vivaldi-bin",
     // Windows archivers
     "7z.exe", "7zFM.exe", "7zG.exe", "winrar.exe", "tar",  "unzip.exe", "winscp.exe",
     // macOS/Linux archivers and fetch tools
     "unzip", "tar", "bsdtar", "curl", "wget",
     // Version control / package managers
     "git", "git.exe", "gh", "gh.exe", "npm", "npm.exe", "node", "node.exe",
     "pip", "pip3", "python", "python3", "python.exe",
     // Shells / script runners
     "powershell.exe", "pwsh.exe", "cmd.exe", "wscript.exe", "cscript.exe",
     "bash", "zsh", "sh", "fish", "dash"
   ) and
   file.path : ("?:\\*\\.vscode\\tasks.json", "/*/.vscode/tasks.json")]
  [process where event.type == "start" and event.action in ("start", "exec") and
   process.name in ("code", "cursor", "Code.exe", "Cursor.exe", "codium", "VSCodium.exe", "windsurf", "Windsurf.exe") and
   process.args == "."]
'''

min_endpoint_version = "8.16.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0

[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 1

[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0

[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 1

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


[[threat.technique]]
id = "T1566"
name = "Phishing"
reference = "https://attack.mitre.org/techniques/T1566/"
[[threat.technique.subtechnique]]
id = "T1566.002"
name = "Spearphishing Link"
reference = "https://attack.mitre.org/techniques/T1566/002/"



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

[internal]
min_endpoint_version = "8.16.0"

Stages and Predicates

Stage 1: file

[file where event.action in ("creation", "modification") and file.name == "tasks.json" and
   process.name in (
     "chrome.exe", "msedge.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe",
     "Google Chrome", "Google Chrome Helper", "Chromium", "Chromium Helper",
     "firefox", "Firefox", "Safari", "SafariTP",
     "Brave Browser", "Opera", "Vivaldi", "Arc",
     "google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
     "firefox", "firefox-esr", "brave-browser", "opera", "vivaldi-bin",
     "7z.exe", "7zFM.exe", "7zG.exe", "winrar.exe", "tar",  "unzip.exe", "winscp.exe",
     "unzip", "tar", "bsdtar", "curl", "wget",
     "git", "git.exe", "gh", "gh.exe", "npm", "npm.exe", "node", "node.exe",
     "pip", "pip3", "python", "python3", "python.exe",
     "powershell.exe", "pwsh.exe", "cmd.exe", "wscript.exe", "cscript.exe",
     "bash", "zsh", "sh", "fish", "dash"
   ) and
   file.path : ("?:\\*\\.vscode\\tasks.json", "/*/.vscode/tasks.json")]

Stage 2: process

[process where event.type == "start" and event.action in ("start", "exec") and
   process.name in ("code", "cursor", "Code.exe", "Cursor.exe", "codium", "VSCodium.exe", "windsurf", "Windsurf.exe") and
   process.args == "."]

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event.actionin
  • creation
  • exec
  • modification
  • start
field:"EventType" kind:in
event.typeeq
  • start
field:"event.type" kind:eq value:"start"
file.nameeq
  • tasks.json
field:"file.name" kind:eq value:"tasks.json"
file.pathwildcard
  • /*/.vscode/tasks.json
  • ?:\*\.vscode\tasks.json
field:"TargetFilename" kind:wildcard
process.argseq
  • .
field:"process.args" kind:eq value:"."
process.namein
  • 7z.exe
  • 7zFM.exe
  • 7zG.exe
  • Arc
  • Brave Browser
  • Chromium
  • Chromium Helper
  • Code.exe
  • Cursor.exe
  • Firefox
  • Google Chrome
  • Google Chrome Helper
  • Opera
  • Safari
  • SafariTP
  • VSCodium.exe
  • Vivaldi
  • Windsurf.exe
  • bash
  • brave-browser
  • brave.exe
  • bsdtar
  • chrome.exe
  • chromium
  • chromium-browser
  • cmd.exe
  • code
  • codium
  • cscript.exe
  • curl
  • cursor
  • dash
  • firefox
  • firefox-esr
  • firefox.exe
  • fish
  • gh
  • gh.exe
  • git
  • git.exe
  • +28 more values (see full rule source)
field:"process_name" kind:in