Detection rules › Elastic

Discovery of GitHub Actions Runner Process PID

Time window
3s
Sequence by
process.parent.entity_id
Source
github.com/elastic/protections-artifacts

This rule detects the discovery of the GitHub Actions Runner process PID using the pgrep command. Adversaries may use this technique to identify the PID of the GitHub Actions Runner process, which can be used to execute commands on the runner host. This behavior may indicate malicious or unexpected workflow activity, including code execution, file manipulation, or network exfiltration initiated through a compromised repository or unauthorized workflow.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

[rule]
description = """
This rule detects the discovery of the GitHub Actions Runner process PID using the pgrep command. Adversaries may use
this technique to identify the PID of the GitHub Actions Runner process, which can be used to execute commands on the
runner host. This behavior may indicate malicious or unexpected workflow activity, including code execution, file
manipulation, or network exfiltration initiated through a compromised repository or unauthorized workflow.
"""
id = "d908caa5-2d4c-4ba7-9ce8-5f1ff4315397"
license = "Elastic License v2"
name = "Discovery of GitHub Actions Runner Process PID"
os_list = ["linux", "macos"]
reference = [
    "https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise",
    "https://www.stepsecurity.io/blog/trivy-compromised-a-second-time---malicious-v0-69-4-release",
    "https://www.crowdstrike.com/en-us/blog/from-scanner-to-stealer-inside-the-trivy-action-supply-chain-compromise/",
]
version = "1.0.2"

query = '''
sequence by process.parent.entity_id with maxspan=3s
  [process where event.type == "start" and event.action == "exec" and process.name == "pgrep" and
  process.args in ("Runner.Listener", "Runner.Worker", "Runner.PluginHost", "run.sh", "svc.sh", "runsvc.sh")] as event0
  [process where event.type == "start" and event.action == "exec" and process.name == "pgrep" and
  not startswith~(process.command_line, event0.process.command_line) and
  process.args in ("Runner.Listener", "Runner.Worker", "Runner.PluginHost", "run.sh", "svc.sh", "runsvc.sh")]
'''

min_endpoint_version = "8.4.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.tactic]
id = "TA0001"
name = "Initial Access"
reference = "https://attack.mitre.org/tactics/TA0001/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"


[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1057"
name = "Process Discovery"
reference = "https://attack.mitre.org/techniques/T1057/"


[threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"

[internal]
min_endpoint_version = "8.4.0"

Stages and Predicates

Ordered sequence: each step below must occur in order within 3s, correlated by process.parent.entity_id.

Stage 1: process

[process where event.type == "start" and event.action == "exec" and process.name == "pgrep" and
  process.args in ("Runner.Listener", "Runner.Worker", "Runner.PluginHost", "run.sh", "svc.sh", "runsvc.sh")] as event0

Stage 2: process

[process where event.type == "start" and event.action == "exec" and process.name == "pgrep" and
  not startswith~(process.command_line, event0.process.command_line) and
  process.args in ("Runner.Listener", "Runner.Worker", "Runner.PluginHost", "run.sh", "svc.sh", "runsvc.sh")]

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.command_linestarts_withevent0.process.command_lineexcludes:process.command_line field:"process.command_line" value:"event0.process.command_line"

Indicators

These rows show field, operator, and value matches.