Potential File Download via a Headless Browser
Identifies headless browser execution from a suspicious parent process with arguments consistent with scripted retrieval. Adversaries use browsers because they are trusted, signed binaries that proxy and application-control policies allow through, bypassing restrictions on direct download tools.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2024/05/10"
3integration = ["endpoint", "windows", "system", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
4maturity = "production"
5updated_date = "2026/03/30"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies headless browser execution from a suspicious parent process with arguments consistent with scripted retrieval. Adversaries use browsers because they are trusted, signed binaries that proxy and application-control policies allow through, bypassing restrictions on direct download tools.
11"""
12from = "now-9m"
13index = [
14 "endgame-*",
15 "logs-crowdstrike.fdr*",
16 "logs-endpoint.events.process-*",
17 "logs-m365_defender.event-*",
18 "logs-sentinel_one_cloud_funnel.*",
19 "logs-system.security*",
20 "logs-windows.forwarded*",
21 "logs-windows.sysmon_operational-*",
22 "winlogbeat-*",
23]
24language = "eql"
25license = "Elastic License v2"
26name = "Potential File Download via a Headless Browser"
27references = ["https://lolbas-project.github.io/lolbas/Binaries/Msedge/"]
28risk_score = 73
29rule_id = "5f2f463e-6997-478c-8405-fb41cc283281"
30severity = "high"
31tags = [
32 "Domain: Endpoint",
33 "OS: Windows",
34 "Use Case: Threat Detection",
35 "Tactic: Command and Control",
36 "Resources: Investigation Guide",
37 "Data Source: Windows",
38 "Data Source: Elastic Endgame",
39 "Data Source: Elastic Defend",
40 "Data Source: Windows Security Event Logs",
41 "Data Source: Microsoft Defender for Endpoint",
42 "Data Source: SentinelOne",
43 "Data Source: Sysmon",
44 "Data Source: Crowdstrike",
45]
46timestamp_override = "event.ingested"
47type = "eql"
48
49query = '''
50process where host.os.type == "windows" and event.type == "start" and
51 process.name : ("chrome.exe", "msedge.exe", "brave.exe", "browser.exe", "dragon.exe", "vivaldi.exe") and
52 process.args : "--headless*" and
53 process.args : ("--dump-dom", "*http*", "data:text/html;base64,*") and
54 process.parent.name :
55 ("cmd.exe", "powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe", "conhost.exe", "msiexec.exe",
56 "explorer.exe", "rundll32.exe", "winword.exe", "excel.exe", "onenote.exe", "hh.exe", "powerpnt.exe", "forfiles.exe",
57 "pcalua.exe", "wmiprvse.exe") and
58 not process.executable : (
59 "?:\\inetpub\\wwwroot\\*\\ext\\modules\\html2pdf\\bin\\chrome\\*\\chrome-win64\\chrome.exe",
60 "\\Device\\HarddiskVolume*\\inetpub\\wwwroot\\*\\ext\\modules\\html2pdf\\bin\\chrome\\*\\chrome-win64\\chrome.exe"
61 )
62'''
63
64note = """## Triage and analysis
65
66### Investigating Potential File Download via a Headless Browser
67
68#### Possible investigation steps
69
70- What headless pattern does the command line express, and is the browser the installed product?
71 - Why: this rule fires on three distinct retrieval patterns -- remote URL fetch, inline base64 HTML decode ("data:text/html;base64"), or DOM dump ("--dump-dom") -- and each requires different follow-on evidence.
72 - Focus: `process.command_line` and `process.working_directory` to identify the retrieval pattern and output destination; confirm the browser is the installed product via `process.executable`, `process.code_signature.subject_name`, and `process.code_signature.trusted`.
73 - Implication: retrieval intent is stronger when the command line targets external content, decodes base64, or redirects output to unusual paths, especially when the browser is unsigned, portable, or renamed; more explainable when the arguments match a rendering or automation workflow and the browser is the standard signed installation.
74
75- Does the parent, ancestry, and user-host pattern explain why a browser is being driven headlessly?
76 - Why: the same browser arguments mean different things when launched by a web-rendering service than when launched by a script host, Office application, or interactive shell.
77 - Focus: `process.parent.executable`, `process.parent.command_line`, `process.Ext.ancestry`, and `process.Ext.session_info.logon_type`; also check whether `user.id` and `host.id` fit a role where headless browser automation is expected.
78 - Implication: more concerning if launched by a script host, Office process, MSI, WMI, or an unexpected interactive session, or when the user-host pair should not be running headless browsers; more explainable if the ancestry resolves to a recognized rendering service or automation component for that host role.
79
80- Do network events show the browser reaching destinations consistent with the claimed workflow?
81 - Focus: same-host network events scoped to the alert's `process.entity_id`, using `dns.resolved_ip` to bridge `dns.question.name` to `destination.ip` and treating `destination.as.organization.name` as ownership context rather than a verdict. $investigate_2
82 - Hint: if `process.entity_id` is not available, stay on the same `host.id` and alert window and use `dns.question.name`, `dns.resolved_ip`, and `destination.ip` to test whether the browser likely reached the fetched content.
83 - Implication: delivery risk increases when the browser reaches rare public destinations or infrastructure unrelated to the workflow, or when another process connects to an exposed debugging port; risk falls when destinations align with recognized internal services or known automation targets. Missing network telemetry is unresolved, not benign.
84
85- Do file events or child processes from the browser show downloaded, decoded, or staged artifacts?
86 - Focus: file events scoped to `process.entity_id` (`file.path`, `file.origin_url`, `file.Ext.windows.zone_identifier`, `file.Ext.header_bytes`), child process activity, and later `process.executable` reuse of a written path.
87 - Implication: more likely delivery when the browser writes scripts, executables, archives, or decoded content to user-writable or deceptive paths, spawns child processes, or the artifact later appears in execution telemetry; less concerning when output stays in a renderer cache or report directory with no suspicious reuse.
88
89- If the local browser, destination, or artifact evidence stays suspicious or unresolved, does related alert history show isolated automation or broader download activity on this user or host?
90 - Focus: related alerts for `host.id` and `user.id` in the last 48 hours, checking for sibling transfer tools, non-headless browser automation, or reuse of the same destinations across hosts.
91 - $investigate_0
92 - $investigate_1
93 - Implication: broaden when the same user or host shows repeated delivery behavior across hosts or through sibling tools; keep narrow when both alert views stay within one recognized automation component.
94
95- Escalate when browser identity, command line, destinations, artifacts, or alert scope point to unauthorized headless retrieval or staging; close only when all evidence aligns with a recognized automation workflow; if mixed or incomplete, preserve and escalate.
96
97### False positive analysis
98
99- Server-side rendering, web testing, QA, or browser automation can legitimately start a headless browser with retrieval arguments. Confirm when `process.executable`, `process.parent.executable`, and the `dns.question.name` or `destination.ip` pattern all align with one automation component and no staged artifacts diverge from that workflow. If automation records are unavailable, require the same browser, parent, and destination pattern to recur across prior alerts.
100- Before creating an exception, build on `process.executable`, `process.parent.executable`, `process.code_signature.subject_name`, and `host.id` or `user.id`. Avoid exceptions on `process.name` alone, the "--headless" flag alone, or `host.id` alone.
101
102### Response and remediation
103
104- If confirmed benign, reverse any temporary containment and document the `process.executable`, `process.parent.executable`, `process.command_line`, destination pattern from `dns.question.name` or `destination.ip`, and recurring `user.id` / `host.id` scope that proved the workflow. Create an exception only if that same pattern recurs consistently across prior alerts from this rule.
105- If suspicious but unconfirmed, first preserve the alert's `process.entity_id`, `process.command_line`, related `file.path` outputs, `file.origin_url` provenance, and any linked `dns.question.name`, `dns.resolved_ip`, or `destination.ip` values. Then apply reversible containment such as temporary egress blocks or tighter monitoring of the affected `user.id` or `host.id`. Escalate to host isolation only when the browser, network, or artifact evidence shows material delivery or staging risk.
106- If confirmed malicious, document the alert's `process.entity_id`, `process.command_line`, `process.parent.command_line`, written `file.path` artifacts, `process.hash.sha256`, and confirmed `dns.question.name` or `destination.ip` values before initiating response actions. Prefer endpoint isolation as the first containment step, weighing the host's role before isolating critical infrastructure such as servers, domain controllers, or build systems. If direct endpoint response is unavailable, escalate with the preserved artifact set to the team that can act.
107- After containment, review other `host.id` and `user.id` alerts for the same `dns.question.name`, `destination.ip`, or `process.executable` pattern before deleting artifacts or restoring access. Then block the malicious destinations and downloaded artifact hashes identified during the investigation, eradicate the scripts, archives, browsers, or persistence artifacts uncovered during the artifact and scope review, and remediate the launcher, automation component, or execution-control gap that allowed the headless browser to retrieve content.
108"""
109
110setup = """## Setup
111
112This 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.
113
114Setup instructions: https://ela.st/install-elastic-defend
115
116### Additional data sources
117
118This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
119
120- [CrowdStrike](https://ela.st/crowdstrike-integration)
121- [Microsoft Defender XDR](https://ela.st/m365-defender)
122- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
123- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
124- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
125"""
126
127[rule.investigation_fields]
128field_names = [
129 "@timestamp",
130 "host.name",
131 "host.id",
132 "user.name",
133 "user.id",
134 "user.domain",
135 "process.entity_id",
136 "process.executable",
137 "process.command_line",
138 "process.pe.original_file_name",
139 "process.parent.executable",
140 "process.parent.command_line",
141 "process.code_signature.subject_name",
142 "process.code_signature.trusted",
143 "process.working_directory",
144 "process.hash.sha256",
145]
146
147[[transform.investigate]]
148label = "Alerts associated with the user"
149description = ""
150providers = [
151 [
152 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
153 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
154 ]
155]
156relativeFrom = "now-48h/h"
157relativeTo = "now"
158
159[[transform.investigate]]
160label = "Alerts associated with the host"
161description = ""
162providers = [
163 [
164 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
165 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
166 ]
167]
168relativeFrom = "now-48h/h"
169relativeTo = "now"
170
171[[transform.investigate]]
172label = "Network activity for the alerting process"
173description = ""
174providers = [
175 [
176 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
177 { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
178 { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" }
179 ]
180]
181relativeFrom = "now-1h"
182relativeTo = "now"
183
184[[rule.threat]]
185framework = "MITRE ATT&CK"
186[[rule.threat.technique]]
187id = "T1105"
188name = "Ingress Tool Transfer"
189reference = "https://attack.mitre.org/techniques/T1105/"
190
191[rule.threat.tactic]
192id = "TA0011"
193name = "Command and Control"
194reference = "https://attack.mitre.org/tactics/TA0011/"
Triage and analysis
Investigating Potential File Download via a Headless Browser
Possible investigation steps
-
What headless pattern does the command line express, and is the browser the installed product?
- Why: this rule fires on three distinct retrieval patterns -- remote URL fetch, inline base64 HTML decode ("data:text/html;base64"), or DOM dump ("--dump-dom") -- and each requires different follow-on evidence.
- Focus:
process.command_lineandprocess.working_directoryto identify the retrieval pattern and output destination; confirm the browser is the installed product viaprocess.executable,process.code_signature.subject_name, andprocess.code_signature.trusted. - Implication: retrieval intent is stronger when the command line targets external content, decodes base64, or redirects output to unusual paths, especially when the browser is unsigned, portable, or renamed; more explainable when the arguments match a rendering or automation workflow and the browser is the standard signed installation.
-
Does the parent, ancestry, and user-host pattern explain why a browser is being driven headlessly?
- Why: the same browser arguments mean different things when launched by a web-rendering service than when launched by a script host, Office application, or interactive shell.
- Focus:
process.parent.executable,process.parent.command_line,process.Ext.ancestry, andprocess.Ext.session_info.logon_type; also check whetheruser.idandhost.idfit a role where headless browser automation is expected. - Implication: more concerning if launched by a script host, Office process, MSI, WMI, or an unexpected interactive session, or when the user-host pair should not be running headless browsers; more explainable if the ancestry resolves to a recognized rendering service or automation component for that host role.
-
Do network events show the browser reaching destinations consistent with the claimed workflow?
- Focus: same-host network events scoped to the alert's
process.entity_id, usingdns.resolved_ipto bridgedns.question.nametodestination.ipand treatingdestination.as.organization.nameas ownership context rather than a verdict. $investigate_2 - Hint: if
process.entity_idis not available, stay on the samehost.idand alert window and usedns.question.name,dns.resolved_ip, anddestination.ipto test whether the browser likely reached the fetched content. - Implication: delivery risk increases when the browser reaches rare public destinations or infrastructure unrelated to the workflow, or when another process connects to an exposed debugging port; risk falls when destinations align with recognized internal services or known automation targets. Missing network telemetry is unresolved, not benign.
- Focus: same-host network events scoped to the alert's
-
Do file events or child processes from the browser show downloaded, decoded, or staged artifacts?
- Focus: file events scoped to
process.entity_id(file.path,file.origin_url,file.Ext.windows.zone_identifier,file.Ext.header_bytes), child process activity, and laterprocess.executablereuse of a written path. - Implication: more likely delivery when the browser writes scripts, executables, archives, or decoded content to user-writable or deceptive paths, spawns child processes, or the artifact later appears in execution telemetry; less concerning when output stays in a renderer cache or report directory with no suspicious reuse.
- Focus: file events scoped to
-
If the local browser, destination, or artifact evidence stays suspicious or unresolved, does related alert history show isolated automation or broader download activity on this user or host?
- Focus: related alerts for
host.idanduser.idin the last 48 hours, checking for sibling transfer tools, non-headless browser automation, or reuse of the same destinations across hosts.- $investigate_0
- $investigate_1
- Implication: broaden when the same user or host shows repeated delivery behavior across hosts or through sibling tools; keep narrow when both alert views stay within one recognized automation component.
- Focus: related alerts for
-
Escalate when browser identity, command line, destinations, artifacts, or alert scope point to unauthorized headless retrieval or staging; close only when all evidence aligns with a recognized automation workflow; if mixed or incomplete, preserve and escalate.
False positive analysis
- Server-side rendering, web testing, QA, or browser automation can legitimately start a headless browser with retrieval arguments. Confirm when
process.executable,process.parent.executable, and thedns.question.nameordestination.ippattern all align with one automation component and no staged artifacts diverge from that workflow. If automation records are unavailable, require the same browser, parent, and destination pattern to recur across prior alerts. - Before creating an exception, build on
process.executable,process.parent.executable,process.code_signature.subject_name, andhost.idoruser.id. Avoid exceptions onprocess.namealone, the "--headless" flag alone, orhost.idalone.
Response and remediation
- If confirmed benign, reverse any temporary containment and document the
process.executable,process.parent.executable,process.command_line, destination pattern fromdns.question.nameordestination.ip, and recurringuser.id/host.idscope that proved the workflow. Create an exception only if that same pattern recurs consistently across prior alerts from this rule. - If suspicious but unconfirmed, first preserve the alert's
process.entity_id,process.command_line, relatedfile.pathoutputs,file.origin_urlprovenance, and any linkeddns.question.name,dns.resolved_ip, ordestination.ipvalues. Then apply reversible containment such as temporary egress blocks or tighter monitoring of the affecteduser.idorhost.id. Escalate to host isolation only when the browser, network, or artifact evidence shows material delivery or staging risk. - If confirmed malicious, document the alert's
process.entity_id,process.command_line,process.parent.command_line, writtenfile.pathartifacts,process.hash.sha256, and confirmeddns.question.nameordestination.ipvalues before initiating response actions. Prefer endpoint isolation as the first containment step, weighing the host's role before isolating critical infrastructure such as servers, domain controllers, or build systems. If direct endpoint response is unavailable, escalate with the preserved artifact set to the team that can act. - After containment, review other
host.idanduser.idalerts for the samedns.question.name,destination.ip, orprocess.executablepattern before deleting artifacts or restoring access. Then block the malicious destinations and downloaded artifact hashes identified during the investigation, eradicate the scripts, archives, browsers, or persistence artifacts uncovered during the artifact and scope review, and remediate the launcher, automation component, or execution-control gap that allowed the headless browser to retrieve content.
References
Related rules
- Potential File Transfer via Certreq
- Potential Protocol Tunneling via Cloudflared
- Potential Protocol Tunneling via Yuze
- Potential Traffic Tunneling using QEMU
- Remote Desktop File Opened from Suspicious Path