Suspicious Execution with NodeJS
Identifies suspicious Node.js execution patterns, including user-writable runtimes, preload arguments, and inline eval, decode, or child-process usage.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/08/21"
3integration = ["endpoint", "windows", "system", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
4maturity = "production"
5updated_date = "2026/05/01"
6[rule]
7author = ["Elastic"]
8description = """
9Identifies suspicious Node.js execution patterns, including user-writable runtimes, preload arguments, and inline
10eval, decode, or child-process usage.
11"""
12
13from = "now-9m"
14index = [
15 "endgame-*",
16 "logs-crowdstrike.fdr*",
17 "logs-endpoint.events.process-*",
18 "logs-m365_defender.event-*",
19 "logs-sentinel_one_cloud_funnel.*",
20 "logs-system.security*",
21 "logs-windows.forwarded*",
22 "logs-windows.sysmon_operational-*",
23 "winlogbeat-*",
24]
25language = "eql"
26license = "Elastic License v2"
27name = "Suspicious Execution with NodeJS"
28references = [
29 "https://nodejs.org/api/child_process.html",
30 "https://nodejs.org/api/globals.html#atobdata",
31]
32risk_score = 73
33rule_id = "55f711c1-6b4d-4787-930d-c9317a885adf"
34severity = "high"
35tags = [
36 "Domain: Endpoint",
37 "OS: Windows",
38 "Use Case: Threat Detection",
39 "Tactic: Execution",
40 "Resources: Investigation Guide",
41 "Data Source: Elastic Endgame",
42 "Data Source: Elastic Defend",
43 "Data Source: Windows Security Event Logs",
44 "Data Source: Microsoft Defender XDR",
45 "Data Source: Sysmon",
46 "Data Source: SentinelOne",
47 "Data Source: Crowdstrike",
48]
49timestamp_override = "event.ingested"
50type = "eql"
51
52query = '''
53process where host.os.type == "windows" and event.type == "start" and
54
55(process.name : "node.exe" or ?process.pe.original_file_name == "node.exe" or ?process.code_signature.subject_name : "OpenJS Foundation") and
56
57(
58 (process.executable : ("?:\\Users\\*\\AppData\\*\\node.exe", "\\Device\\HarddiskVolume*\\Users\\*\\AppData\\*\\node.exe") and process.args : "*.js") or
59
60 (process.args : "-r" and process.parent.name : "powershell.exe") or
61
62 process.command_line : ("*eval(*", "*atob(*", "*require*child_process*")
63)
64'''
65
66note = """## Triage and analysis
67
68### Investigating Suspicious Execution with NodeJS
69
70#### Possible investigation steps
71
72- Which Node execution path did the alert capture?
73 - Focus: `process.executable`, `process.command_line`, `process.parent.name`, and `process.pe.original_file_name`.
74 - Implication: escalate faster when the match is a user-writable AppData "node.exe", PowerShell-launched preload, or inline decode/spawn pattern; lower suspicion when parent and command-line evidence show a recognized version-manager, IDE, package-manager, or test-runner pattern.
75
76- Do the runtime identity and launcher context fit recognized Node use?
77 - Focus: `process.executable`, `process.pe.original_file_name`, `process.code_signature.subject_name`, `process.code_signature.trusted`, `process.parent.command_line`, `user.id`, and `host.id`.
78 - Implication: escalate when the runtime is unsigned, renamed, mismatched to "node.exe", staged from Temp/AppData outside a recognized toolchain, or launched by PowerShell, Office, a browser, an archive utility, or a download path without matching IDE/package/build context; lower suspicion only when runtime identity and parent chain fit the same recurring Node workflow for that user or host. Identity alone does not clear suspicious arguments.
79
80- What do the arguments show about preload, script, or inline execution intent?
81 - Why: "-r" / "--require" preloads a module at startup; "child_process" enables OS subprocess creation.
82 - Focus: `process.command_line` and the script or preload path parsed from it.
83 - Implication: escalate when Node preloads an unexpected module, decodes inline content with 'atob(' or 'eval(', or references "child_process"; lower suspicion when the target is a recognized preload such as a test harness, transpiler, or source-map helper inside the same project tree.
84
85- If endpoint file telemetry is available, what provenance exists for the script or preload module?
86 - Focus: recover file events with `host.id` + `process.entity_id`, or `host.id` + `process.pid` + a tight alert window as weaker fallback; inspect `file.path`, `file.origin_url`, `file.Ext.windows.zone_identifier`, and `file.Ext.original.path`. $investigate_2
87 - Hint: missing file telemetry is unresolved, not benign; use parsed command-line paths and parent context as weaker evidence.
88 - Implication: escalate when the script or module was downloaded, extracted, renamed, or staged into AppData/Temp shortly before execution; lower suspicion when it stays in a stable repository, package cache, or product install tree consistent with the parent workflow.
89
90- If child-process or endpoint network telemetry is available, what did Node do next?
91 - Focus: recover child and network events with `host.id` + `process.entity_id`, or `host.id` + `process.pid` + the post-start window as weaker fallback; inspect child `process.name` / `process.executable`, DNS `dns.question.name`, and connection `destination.ip` / `destination.port`.
92 - $investigate_3
93 - $investigate_4
94 - Hint: separate DNS events from connection events before interpreting destinations; missing child or network telemetry is unresolved, not benign.
95 - Implication: escalate when Node quickly launches shells, LOLBins, archivers, credential tooling, or reaches externally routable destinations unrelated to the workflow; lower suspicion when child activity and destinations stay bounded to recognized local development, build, package-registry, or deployment services.
96
97- If local evidence stays suspicious or unresolved, do related alerts show broader scripting, download, persistence, or beaconing activity?
98 - Focus: same-`user.id` related alerts or process events, especially PowerShell, archive, downloader, persistence, and outbound-connection activity.
99 - Hint: if `user.id` is missing or ambiguous, review same-host alerts and process events for `host.id` in the last 48 hours.
100 - $investigate_0
101 - $investigate_1
102 - Implication: expand scope when the host or user shows staged payload delivery, repeated Node misuse, persistence, or beaconing; keep scope local when behavior is isolated and local evidence supports one recognized workflow.
103
104- Escalate when branch, runtime, argument, lineage, or recovered artifact/child/network evidence shows staged script, unrecognized preload, inline decode, or spawn abuse; close only when those categories tightly support one recognized workflow with no contradictions; preserve artifacts and escalate when evidence is mixed or incomplete.
105
106### False positive analysis
107
108- Developer tooling, version managers, IDEs, package managers, and build/test runners can legitimately run "node.exe" from user-space paths or use "-r" preloads. Confirm one workflow: runtime path/hash/signer, parent, command line, and referenced script or preload path all align with the same toolchain. Without inventory or build records, telemetry-only closure requires exact workflow recurrence for the same `user.id` or `host.id` cohort plus no contradictory file, child-process, or network evidence; do not close on recurrence alone.
109- Treat partial matches as unresolved. An OpenJS signer, "node.exe" name, or familiar parent does not explain AppData execution, inline decode/eval, or child-process behavior by itself. Before creating an exception, validate recurrence of the same Node binary, argument pattern, parent context, and script or preload path; avoid exceptions on `process.name` or `process.code_signature.subject_name` alone.
110
111### Response and remediation
112
113- If confirmed benign, reverse temporary containment and document the exact Node workflow: runtime path/hash/signer, parent launcher, command line, script or preload path, and `user.id` / `host.id` scope. Create an exception only when the same workflow recurs consistently across prior alerts from this rule.
114- If suspicious but unconfirmed, preserve the process start event, command line, binary hash/signature, script or preload artifact, child process chain, and any recovered DNS or connection events before containment. Apply reversible containment tied to the finding, such as temporary destination blocking, script quarantine, or heightened monitoring on the affected `host.id` and `user.id`. Escalate to host isolation only when follow-on execution, persistence, or outbound activity confirms broader compromise and host criticality allows interruption.
115- If confirmed malicious, preserve `process.entity_id` or `process.pid` with `host.id` and time, parent process context, `process.command_line`, `process.hash.sha256`, referenced script or preload paths, child-process lineage, and confirmed network indicators before terminating Node or isolating the host. If direct endpoint response is unavailable, hand off that artifact set to the team that can isolate the system or block destinations.
116- Scope related hosts and users for the same runtime hash, suspicious command-line pattern, script/preload paths, child-process lineage, and network indicators before deleting scripts, modules, or staged payloads. Then remove only the malicious artifacts identified during triage and remediate the delivery path or launcher that led to Node execution.
117- Post-incident hardening: restrict unrecognized "node.exe" execution from user-writable paths, retain process-start, file-provenance, and network telemetry, and document adjacent variants found during triage, such as renamed Node runtimes, packaged Electron launchers, alternate preload patterns, or `--require` abuse without PowerShell."""
118
119setup = """## Setup
120
121This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
122
123Setup instructions: https://ela.st/install-elastic-defend
124
125### Additional data sources
126
127This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
128
129- [CrowdStrike](https://ela.st/crowdstrike-integration)
130- [Microsoft Defender XDR](https://ela.st/m365-defender)
131- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
132- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
133- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
134"""
135
136[rule.investigation_fields]
137field_names = [
138 "@timestamp",
139 "host.id",
140 "user.id",
141 "process.entity_id",
142 "process.pid",
143 "process.executable",
144 "process.command_line",
145 "process.args",
146 "process.working_directory",
147 "process.pe.original_file_name",
148 "process.code_signature.subject_name",
149 "process.code_signature.trusted",
150 "process.hash.sha256",
151 "process.parent.executable",
152 "process.parent.command_line",
153]
154
155[transform]
156
157[[transform.investigate]]
158label = "Alerts associated with the user"
159description = ""
160providers = [
161 [
162 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
163 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
164 ]
165]
166relativeFrom = "now-48h/h"
167relativeTo = "now"
168
169[[transform.investigate]]
170label = "Alerts associated with the host"
171description = ""
172providers = [
173 [
174 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
175 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
176 ]
177]
178relativeFrom = "now-48h/h"
179relativeTo = "now"
180
181[[transform.investigate]]
182label = "File events for the Node process"
183description = ""
184providers = [
185 [
186 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
187 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
188 { excluded = false, field = "event.category", queryType = "phrase", value = "file", valueType = "string" }
189 ]
190]
191relativeFrom = "now-1h"
192relativeTo = "now"
193
194[[transform.investigate]]
195label = "Child processes spawned by Node"
196description = ""
197providers = [
198 [
199 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
200 { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
201 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
202 ]
203]
204relativeFrom = "now-1h"
205relativeTo = "now"
206
207[[transform.investigate]]
208label = "Network events for the Node process"
209description = ""
210providers = [
211 [
212 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
213 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
214 { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" }
215 ]
216]
217relativeFrom = "now-1h"
218relativeTo = "now"
219
220[[rule.threat]]
221framework = "MITRE ATT&CK"
222
223[[rule.threat.technique]]
224id = "T1059"
225name = "Command and Scripting Interpreter"
226reference = "https://attack.mitre.org/techniques/T1059/"
227
228[[rule.threat.technique.subtechnique]]
229id = "T1059.007"
230name = "JavaScript"
231reference = "https://attack.mitre.org/techniques/T1059/007/"
232
233[rule.threat.tactic]
234id = "TA0002"
235name = "Execution"
236reference = "https://attack.mitre.org/tactics/TA0002/"
237
238[[rule.threat]]
239framework = "MITRE ATT&CK"
240
241[[rule.threat.technique]]
242id = "T1027"
243name = "Obfuscated Files or Information"
244reference = "https://attack.mitre.org/techniques/T1027/"
245
246[[rule.threat.technique.subtechnique]]
247id = "T1027.010"
248name = "Command Obfuscation"
249reference = "https://attack.mitre.org/techniques/T1027/010/"
250
251[rule.threat.tactic]
252id = "TA0005"
253name = "Defense Evasion"
254reference = "https://attack.mitre.org/tactics/TA0005/"
Triage and analysis
Investigating Suspicious Execution with NodeJS
Possible investigation steps
-
Which Node execution path did the alert capture?
- Focus:
process.executable,process.command_line,process.parent.name, andprocess.pe.original_file_name. - Implication: escalate faster when the match is a user-writable AppData "node.exe", PowerShell-launched preload, or inline decode/spawn pattern; lower suspicion when parent and command-line evidence show a recognized version-manager, IDE, package-manager, or test-runner pattern.
- Focus:
-
Do the runtime identity and launcher context fit recognized Node use?
- Focus:
process.executable,process.pe.original_file_name,process.code_signature.subject_name,process.code_signature.trusted,process.parent.command_line,user.id, andhost.id. - Implication: escalate when the runtime is unsigned, renamed, mismatched to "node.exe", staged from Temp/AppData outside a recognized toolchain, or launched by PowerShell, Office, a browser, an archive utility, or a download path without matching IDE/package/build context; lower suspicion only when runtime identity and parent chain fit the same recurring Node workflow for that user or host. Identity alone does not clear suspicious arguments.
- Focus:
-
What do the arguments show about preload, script, or inline execution intent?
- Why: "-r" / "--require" preloads a module at startup; "child_process" enables OS subprocess creation.
- Focus:
process.command_lineand the script or preload path parsed from it. - Implication: escalate when Node preloads an unexpected module, decodes inline content with 'atob(' or 'eval(', or references "child_process"; lower suspicion when the target is a recognized preload such as a test harness, transpiler, or source-map helper inside the same project tree.
-
If endpoint file telemetry is available, what provenance exists for the script or preload module?
- Focus: recover file events with
host.id+process.entity_id, orhost.id+process.pid+ a tight alert window as weaker fallback; inspectfile.path,file.origin_url,file.Ext.windows.zone_identifier, andfile.Ext.original.path. $investigate_2 - Hint: missing file telemetry is unresolved, not benign; use parsed command-line paths and parent context as weaker evidence.
- Implication: escalate when the script or module was downloaded, extracted, renamed, or staged into AppData/Temp shortly before execution; lower suspicion when it stays in a stable repository, package cache, or product install tree consistent with the parent workflow.
- Focus: recover file events with
-
If child-process or endpoint network telemetry is available, what did Node do next?
- Focus: recover child and network events with
host.id+process.entity_id, orhost.id+process.pid+ the post-start window as weaker fallback; inspect childprocess.name/process.executable, DNSdns.question.name, and connectiondestination.ip/destination.port.- $investigate_3
- $investigate_4
- Hint: separate DNS events from connection events before interpreting destinations; missing child or network telemetry is unresolved, not benign.
- Implication: escalate when Node quickly launches shells, LOLBins, archivers, credential tooling, or reaches externally routable destinations unrelated to the workflow; lower suspicion when child activity and destinations stay bounded to recognized local development, build, package-registry, or deployment services.
- Focus: recover child and network events with
-
If local evidence stays suspicious or unresolved, do related alerts show broader scripting, download, persistence, or beaconing activity?
- Focus: same-
user.idrelated alerts or process events, especially PowerShell, archive, downloader, persistence, and outbound-connection activity. - Hint: if
user.idis missing or ambiguous, review same-host alerts and process events forhost.idin the last 48 hours.- $investigate_0
- $investigate_1
- Implication: expand scope when the host or user shows staged payload delivery, repeated Node misuse, persistence, or beaconing; keep scope local when behavior is isolated and local evidence supports one recognized workflow.
- Focus: same-
-
Escalate when branch, runtime, argument, lineage, or recovered artifact/child/network evidence shows staged script, unrecognized preload, inline decode, or spawn abuse; close only when those categories tightly support one recognized workflow with no contradictions; preserve artifacts and escalate when evidence is mixed or incomplete.
False positive analysis
- Developer tooling, version managers, IDEs, package managers, and build/test runners can legitimately run "node.exe" from user-space paths or use "-r" preloads. Confirm one workflow: runtime path/hash/signer, parent, command line, and referenced script or preload path all align with the same toolchain. Without inventory or build records, telemetry-only closure requires exact workflow recurrence for the same
user.idorhost.idcohort plus no contradictory file, child-process, or network evidence; do not close on recurrence alone. - Treat partial matches as unresolved. An OpenJS signer, "node.exe" name, or familiar parent does not explain AppData execution, inline decode/eval, or child-process behavior by itself. Before creating an exception, validate recurrence of the same Node binary, argument pattern, parent context, and script or preload path; avoid exceptions on
process.nameorprocess.code_signature.subject_namealone.
Response and remediation
- If confirmed benign, reverse temporary containment and document the exact Node workflow: runtime path/hash/signer, parent launcher, command line, script or preload path, and
user.id/host.idscope. Create an exception only when the same workflow recurs consistently across prior alerts from this rule. - If suspicious but unconfirmed, preserve the process start event, command line, binary hash/signature, script or preload artifact, child process chain, and any recovered DNS or connection events before containment. Apply reversible containment tied to the finding, such as temporary destination blocking, script quarantine, or heightened monitoring on the affected
host.idanduser.id. Escalate to host isolation only when follow-on execution, persistence, or outbound activity confirms broader compromise and host criticality allows interruption. - If confirmed malicious, preserve
process.entity_idorprocess.pidwithhost.idand time, parent process context,process.command_line,process.hash.sha256, referenced script or preload paths, child-process lineage, and confirmed network indicators before terminating Node or isolating the host. If direct endpoint response is unavailable, hand off that artifact set to the team that can isolate the system or block destinations. - Scope related hosts and users for the same runtime hash, suspicious command-line pattern, script/preload paths, child-process lineage, and network indicators before deleting scripts, modules, or staged payloads. Then remove only the malicious artifacts identified during triage and remediate the delivery path or launcher that led to Node execution.
- Post-incident hardening: restrict unrecognized "node.exe" execution from user-writable paths, retain process-start, file-provenance, and network telemetry, and document adjacent variants found during triage, such as renamed Node runtimes, packaged Electron launchers, alternate preload patterns, or
--requireabuse without PowerShell.
References
Related rules
- Potential Foxmail Exploitation
- Suspicious Cmd Execution via WMI
- Suspicious Execution from a WebDav Share
- Suspicious JavaScript Execution via Deno
- Clearing Windows Console History