Suspicious Python Shell Command Execution
Detects the execution of suspicious shell commands via the Python interpreter. Attackers may use Python to execute shell commands to gain access to the system or to perform other malicious activities, such as credential access, data exfiltration, or lateral movement.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/03/26"
3integration = ["endpoint"]
4maturity = "production"
5updated_date = "2026/04/10"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects the execution of suspicious shell commands via the Python interpreter. Attackers
11may use Python to execute shell commands to gain access to the system or to perform other
12malicious activities, such as credential access, data exfiltration, or lateral movement.
13"""
14from = "now-9m"
15language = "esql"
16license = "Elastic License v2"
17name = "Suspicious Python Shell Command Execution"
18note = """## Triage and analysis
19
20> **Disclaimer**:
21> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
22
23### Investigating Suspicious Python Shell Command Execution
24
25This rule flags Linux or macOS activity where Python rapidly launches multiple shell commands through sh/bash-style interpreters, a strong sign that a script is driving hands-on execution rather than normal application behavior. An attacker might use a Python backdoor to run `sh -c` commands such as `whoami`, `uname`, `env`, `find`, and `curl` in quick succession to profile the host, locate data, and pull down follow-on tools.
26
27### Possible investigation steps
28
29- Reconstruct the full process tree around the Python parent to identify the originating script or module, execution path, user context, and whether it was launched by an interactive session, scheduled task, service, container runtime, or approved automation.
30- Review the Python code or script content that spawned the shells, along with recent file creation or modification and package installation activity, to determine whether it is legitimate application logic or an unexpected payload introduced in temporary, user, or application directories.
31- Compare the clustered shell commands with any immediate follow-on behavior such as outbound network connections, tool downloads, archive creation, credential store access, or additional interpreter launches to assess whether the activity moved from discovery into payload delivery or exfiltration.
32- Pivot on the same host and Python execution lineage for prior and subsequent events to uncover persistence or lateral movement indicators, including cron or systemd changes, launchd modifications, SSH activity, or repeated execution patterns across other endpoints.
33- Validate with the asset or application owner whether the behavior matches known deployment, build, or administrative workflows, and if it does not, isolate the host and collect memory, script artifacts, and shell history for deeper analysis.
34
35### False positive analysis
36
37- A legitimate Python administration or deployment script may call `sh -c` to run discovery and download commands such as `whoami`, `uname`, `env`, `find`, or `curl` during host setup; verify the parent Python script path, user, and working directory match an approved maintenance job and that the command set is expected for that script.
38- A Python application on Linux or macOS may spawn shell wrappers during startup, diagnostics, or update checks and generate several distinct commands within a minute; confirm the Python executable and child shell activity originate from the expected application directory and correlate with a recent authorized install, upgrade, or troubleshooting session.
39
40### Response and remediation
41
42- Isolate the affected Linux or macOS host from the network, terminate the malicious Python process and any spawned `sh -c` or `bash -c` children, and block any external IPs, domains, or download URLs the script contacted.
43- Preserve and quarantine the Python script, shell history, downloaded payloads, and files created in temporary, user, or application directories, then remove attacker persistence such as cron jobs, systemd service or timer units, launchd plists, login scripts, and unauthorized `authorized_keys` entries.
44- Restore the system to a known-good state by removing attacker-created files only after collection, reinstalling or repairing modified packages and startup items, and reimaging the host if system binaries, security tools, or core configuration files were altered.
45- Rotate credentials and secrets exposed on the host, including local accounts, SSH keys, API tokens, and application or cloud credentials, especially if the shell activity included `env`, keychain access, history review, or reads from credential files.
46- Escalate to incident response immediately if the Python-launched shells used `curl` or `wget` to fetch payloads, established outbound sessions to untrusted infrastructure, touched multiple endpoints, or showed evidence of credential theft, persistence, or data collection.
47- Harden the environment by restricting Python and shell execution from temporary or user-writable paths, limiting which users and services can invoke shell interpreters, tightening egress controls, and adding detections for Python spawning shell commands, new cron or launchd items, and unauthorized SSH key changes.
48"""
49risk_score = 47
50rule_id = "b42e4b88-fc4a-417b-a45e-4d4a3db9fd41"
51severity = "medium"
52tags = [
53 "Domain: Endpoint",
54 "OS: Linux",
55 "OS: macOS",
56 "Use Case: Threat Detection",
57 "Tactic: Execution",
58 "Data Source: Elastic Defend",
59 "Resources: Investigation Guide",
60]
61type = "esql"
62query = '''
63FROM logs-endpoint.events.process-* METADATA _id, _version, _index
64
65| WHERE host.os.type in ("linux", "macos") and event.type == "start" and TO_LOWER(process.parent.name) like "python*" and
66 process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox") and
67 KQL("""event.action:"exec" and process.args:("-c" or "-cl" or "-lc")""")
68
69// truncate timestamp to 1-minute window
70| EVAL Esql.time_window_date_trunc = DATE_TRUNC(1 minutes, @timestamp)
71
72| EVAL Esql.process_command_line_patterns = CASE(
73 process.command_line like "*grep*", "grep",
74 process.command_line like "*find*", "find",
75 process.command_line like "*curl*", "curl",
76 process.command_line like "*env *", "environment_enumeration",
77 process.command_line like "*wget*", "wget",
78 process.command_line like "*whoami*" or process.command_line like "*uname*" or process.command_line like "*hostname*", "discovery", "other"
79)
80
81| KEEP
82 @timestamp,
83 _id,
84 _index,
85 _version,
86 Esql.process_command_line_patterns,
87 Esql.time_window_date_trunc,
88 host.os.type,
89 event.type,
90 event.action,
91 process.parent.name,
92 process.working_directory,
93 process.parent.working_directory,
94 process.name,
95 process.executable,
96 process.command_line,
97 process.parent.executable,
98 process.parent.entity_id,
99 agent.id,
100 host.name,
101 data_stream.dataset,
102 data_stream.namespace
103
104| STATS
105 Esql.process_command_line_count_distinct = COUNT_DISTINCT(process.command_line),
106 Esql.patterns_count_distinct = COUNT_DISTINCT(Esql.process_command_line_patterns),
107 Esql.process_command_line_values = VALUES(process.command_line),
108 Esql.host_name_values = values(host.name),
109 Esql.agent_id_values = values(agent.id),
110 Esql.data_stream_dataset_values = values(data_stream.dataset),
111 Esql.data_stream_namespace_values = values(data_stream.namespace)
112 BY process.parent.entity_id, agent.id, host.name, Esql.time_window_date_trunc
113
114| SORT Esql.process_command_line_count_distinct DESC
115| WHERE Esql.process_command_line_count_distinct >= 5 AND Esql.patterns_count_distinct >= 4
116'''
117
118[[rule.threat]]
119framework = "MITRE ATT&CK"
120
121[[rule.threat.technique]]
122id = "T1059"
123name = "Command and Scripting Interpreter"
124reference = "https://attack.mitre.org/techniques/T1059/"
125
126[[rule.threat.technique.subtechnique]]
127id = "T1059.006"
128name = "Python"
129reference = "https://attack.mitre.org/techniques/T1059/006/"
130
131[rule.threat.tactic]
132id = "TA0002"
133name = "Execution"
134reference = "https://attack.mitre.org/tactics/TA0002/"
Triage and analysis
Disclaimer: This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.
Investigating Suspicious Python Shell Command Execution
This rule flags Linux or macOS activity where Python rapidly launches multiple shell commands through sh/bash-style interpreters, a strong sign that a script is driving hands-on execution rather than normal application behavior. An attacker might use a Python backdoor to run sh -c commands such as whoami, uname, env, find, and curl in quick succession to profile the host, locate data, and pull down follow-on tools.
Possible investigation steps
- Reconstruct the full process tree around the Python parent to identify the originating script or module, execution path, user context, and whether it was launched by an interactive session, scheduled task, service, container runtime, or approved automation.
- Review the Python code or script content that spawned the shells, along with recent file creation or modification and package installation activity, to determine whether it is legitimate application logic or an unexpected payload introduced in temporary, user, or application directories.
- Compare the clustered shell commands with any immediate follow-on behavior such as outbound network connections, tool downloads, archive creation, credential store access, or additional interpreter launches to assess whether the activity moved from discovery into payload delivery or exfiltration.
- Pivot on the same host and Python execution lineage for prior and subsequent events to uncover persistence or lateral movement indicators, including cron or systemd changes, launchd modifications, SSH activity, or repeated execution patterns across other endpoints.
- Validate with the asset or application owner whether the behavior matches known deployment, build, or administrative workflows, and if it does not, isolate the host and collect memory, script artifacts, and shell history for deeper analysis.
False positive analysis
- A legitimate Python administration or deployment script may call
sh -cto run discovery and download commands such aswhoami,uname,env,find, orcurlduring host setup; verify the parent Python script path, user, and working directory match an approved maintenance job and that the command set is expected for that script. - A Python application on Linux or macOS may spawn shell wrappers during startup, diagnostics, or update checks and generate several distinct commands within a minute; confirm the Python executable and child shell activity originate from the expected application directory and correlate with a recent authorized install, upgrade, or troubleshooting session.
Response and remediation
- Isolate the affected Linux or macOS host from the network, terminate the malicious Python process and any spawned
sh -corbash -cchildren, and block any external IPs, domains, or download URLs the script contacted. - Preserve and quarantine the Python script, shell history, downloaded payloads, and files created in temporary, user, or application directories, then remove attacker persistence such as cron jobs, systemd service or timer units, launchd plists, login scripts, and unauthorized
authorized_keysentries. - Restore the system to a known-good state by removing attacker-created files only after collection, reinstalling or repairing modified packages and startup items, and reimaging the host if system binaries, security tools, or core configuration files were altered.
- Rotate credentials and secrets exposed on the host, including local accounts, SSH keys, API tokens, and application or cloud credentials, especially if the shell activity included
env, keychain access, history review, or reads from credential files. - Escalate to incident response immediately if the Python-launched shells used
curlorwgetto fetch payloads, established outbound sessions to untrusted infrastructure, touched multiple endpoints, or showed evidence of credential theft, persistence, or data collection. - Harden the environment by restricting Python and shell execution from temporary or user-writable paths, limiting which users and services can invoke shell interpreters, tightening egress controls, and adding detections for Python spawning shell commands, new cron or launchd items, and unauthorized SSH key changes.
Related rules
- Execution via OpenClaw Agent
- AWS SSM `SendCommand` with Run Shell Command Parameters
- Execution via GitHub Actions Runner
- GenAI Process Compiling or Generating Executables
- Kubernetes Direct API Request via Curl or Wget