Detection rules › Elastic
Discovery of GitHub Actions Runner Process PID
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
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Discovery |
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.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.command_line | starts_with | event0.process.command_line | excludes:process.command_line field:"process.command_line" value:"event0.process.command_line" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq value:"exec" |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.args | in |
| field:"process.args" kind:in |
process.name | eq |
| field:"process_name" kind:eq value:"pgrep" |