The U.S. Department of Justice, working with international law enforcement partners, has disrupted the Gootloader malware operation: more than 100 servers were taken down or cleaned of the malware, U.S. domain names used for delivery and command-and-control were seized, and victims worldwide are being notified. The operation had compromised approximately 25,000 computers.
Here is the part that matters for defenders: seizing C2 infrastructure does not remediate compromised endpoints. Gootloader is a loader — its entire purpose is to stage follow-on payloads. Historically, infections have preceded deployment of ransomware (including REvil/Sodinokibi), Cobalt Strike beacons, IcedID, and SystemBC. If any of those 25,000 machines are in your environment, the operator's infrastructure being seized buys you time — it does not close the incident. The staged payloads, persistence mechanisms, and any lateral movement that already occurred are still your problem.
This post covers how Gootloader operates from a defender's perspective, how to hunt for it retrospectively, and how to remediate.
Technical Analysis: How Gootloader Actually Works
Delivery: SEO Poisoning, Not Phishing
Gootloader's defining characteristic is that it rarely arrives by email. Operators compromise legitimate websites — predominantly WordPress — and inject fake forum threads and Q&A pages optimized for search engine ranking. Victims searching for business document templates (contracts, agreements, financial forms) land on these pages and download a ZIP archive containing an obfuscated JavaScript file.
This has two implications for detection:
- Your email gateway will not save you. The delivery vector is browser-driven downloads of
.ziparchives containing.jsfiles from legitimate-but-compromised domains. - User behavior telemetry matters. The typical execution chain starts with a user double-clicking a
.jsfile from their Downloads folder, which invokeswscript.exe.
Execution Chain
The classic Gootloader execution chain, which defenders should treat as the canonical detection target:
- User downloads
*.zipfrom a search result → extracts a.jsfile (often named to match the search query, e.g.,what_is_a_post_nuptial_agreement 61472.js). wscript.exeexecutes the JS, which drops a second obfuscated JS stage into%APPDATA%with a legitimate-looking filename.- The second stage runs (again via
wscript.exe), which launches PowerShell as a child process of wscript.exe — this parent-child relationship is one of the highest-fidelity signals available. - PowerShell performs reflective injection and executes payloads in memory, fingerprinting the host and pulling follow-on malware.
- Persistence is established via registry Run keys and, in some campaigns, scheduled tasks pointing at the JS or follow-on payloads.
Exploitation Status
- Scale: ~25,000 confirmed infections per the DOJ announcement; over 100 malicious servers and seized domains.
- Follow-on risk: Confirmed history of ransomware enablement. Gootloader has been a documented initial access vector for human-operated ransomware intrusions.
- Post-takedown status: C2 is disrupted, but sinkholing/neutralization of infrastructure is frequently temporary. Operators of comparable loaders (Emotet, Qakbot) have rebuilt after takedowns. Treat this as ongoing risk, not a closed chapter.
- CISA KEV: No CVE applies — this is a malware campaign, not a vulnerability. Do not look for a patch; look for artifacts.
Detection & Response
The highest-fidelity detection opportunities are the wscript.exe → powershell.exe parent-child relationship, JS files executing from user-writable directories (Downloads, AppData), and Run-key persistence referencing script files.
Sigma Rules
---
title: Gootloader - Wscript Spawning PowerShell
id: 3f8a2c41-7b9d-4e51-a6c2-9d1e5f8b3a07
status: experimental
description: Detects PowerShell spawned by Windows Script Host (wscript/cscript), a hallmark of Gootloader's staged JavaScript execution chain.
references:
- https://securityaffairs.com/202997/cyber-crime/gootloader-malware-disrupted-after-infecting-25000-computers.html
- https://attack.mitre.org/techniques/T1059/007/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.t1059.007
- attack.t1059.001
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\wscript.exe'
- '\cscript.exe'
selection_child:
Image|endswith:
- '\powershell.exe'
- '\powershell_ise.exe'
- '\pwsh.exe'
condition: all of selection_*
falsepositives:
- Rare legitimate admin scripts that invoke PowerShell from WSH wrappers
level: high
---
title: Gootloader - JavaScript Execution from User Directories
id: 8c1d4e62-3a5f-4b78-9c01-2e7a6d4f9b15
status: experimental
description: Detects wscript.exe or cscript.exe executing JavaScript files from Downloads, AppData, or Temp directories, consistent with Gootloader SEO-poisoned ZIP delivery.
references:
- https://securityaffairs.com/202997/cyber-crime/gootloader-malware-disrupted-after-infecting-25000-computers.html
- https://attack.mitre.org/techniques/T1204/002/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.t1204.002
logsource:
category: process_creation
product: windows
detection:
selection_img:
Image|endswith:
- '\wscript.exe'
- '\cscript.exe'
selection_path:
CommandLine|contains:
- '\Downloads\'
- '\AppData\Roaming\'
- '\AppData\Local\Temp\'
selection_ext:
CommandLine|contains:
- '.js'
- '.jse'
condition: all of selection_*
falsepositives:
- Some enterprise software installers run JS helpers from temp paths; tune per environment
level: high
---
title: Gootloader - Run Key Persistence Referencing Script Files
id: b5e7f1a3-6c28-4d94-a817-4f2c8e6b1d93
status: experimental
description: Detects registry Run/RunOnce key values pointing to .js, .jse, or .vbs files in user-writable paths, a Gootloader persistence pattern.
references:
- https://securityaffairs.com/202997/cyber-crime/gootloader-malware-disrupted-after-infecting-25000-computers.html
- https://attack.mitre.org/techniques/T1060/
- https://attack.mitre.org/techniques/T1547/001/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1547.001
logsource:
category: registry_set
product: windows
detection:
selection_key:
TargetObject|contains:
- '\CurrentVersion\Run'
selection_value:
Details|contains:
- '.js'
- '.jse'
- '.vbs'
- 'wscript'
selection_path:
Details|contains:
- '\AppData\'
- '\Temp\'
- '\Downloads\'
- '\ProgramData\'
condition: all of selection_*
falsepositives:
- Rare; legitimate software almost never persists scripts from user-writable paths via Run keys
level: critical
KQL — Microsoft Sentinel / Defender
This hunt targets the full Gootloader chain: script-host execution from user paths, the wscript→PowerShell relationship, and persistence artifacts. Run it over a 30–90 day lookback if you suspect historical exposure.
// Gootloader hunt: WSH execution from user paths + wscript spawning PowerShell
let lookback = 90d;
let ScriptHosts = dynamic(["wscript.exe", "cscript.exe"]);
let UserPaths = dynamic(["\\Downloads\\", "\\AppData\\Roaming\\", "\\AppData\\Local\\Temp\\", "\\ProgramData\\"]);
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where FileName in~ (ScriptHosts)
| where ProcessCommandLine has_any (UserPaths)
and ProcessCommandLine has_any (".js", ".jse")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, ProcessId, InitiatingProcessFileName
| join kind=leftouter (
DeviceProcessEvents
| where Timestamp > ago(lookback)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| project ChildTime=Timestamp, DeviceName, ChildCmd=ProcessCommandLine, InitiatingProcessId
) on DeviceName, $left.ProcessId == $right.InitiatingProcessId
| where ChildTime between (Timestamp .. Timestamp + 5m) or isempty(ChildTime)
| summarize by Timestamp, DeviceName, AccountName, ProcessCommandLine, ChildCmd
| sort by Timestamp desc
// Gootloader persistence: Run keys referencing script interpreters or script files
DeviceRegistryEvents
| where Timestamp > ago(90d)
| where RegistryKey has_any ("\\CurrentVersion\\Run", "\\CurrentVersion\\RunOnce")
| where RegistryValueData has_any ("wscript", "cscript", ".js", ".jse", ".vbs")
| where RegistryValueData has_any ("AppData", "ProgramData", "Temp", "Downloads")
| project Timestamp, DeviceName, InitiatingProcessAccountName, RegistryKey, RegistryValueName, RegistryValueData
| sort by Timestamp desc
Velociraptor VQL
Use this as a fleet-wide hunt artifact to surface live script-host execution and persistence artifacts on endpoints you suspect may be among the infected population.
-- Gootloader hunt: live WSH processes with script args + Run-key script persistence
SELECT {
SELECT Pid, Name, CommandLine, Username, CreateTime
FROM pslist()
WHERE Name =~ '(?i)wscript|cscript'
AND CommandLine =~ '(?i)\.js|\.jse|appdata|downloads|temp'
} AS SuspiciousScriptHosts,
{
SELECT Key.Path AS RunKey, ValueName, String(value=ValueData) AS ValueData
FROM stat(filename='')
WHERE FALSE
} AS Placeholder
FROM scope()
-- Gootloader persistence sweep: Run keys containing script interpreters
SELECT Mtime, Key.Path AS KeyPath, Name AS ValueName,
Data.value AS ValueData
FROM foreach(row={
SELECT FullPath FROM glob(globs='HKEY_USERS/*/Software/Microsoft/Windows/CurrentVersion/Run*')
}, query={
SELECT Mtime, Key, Name, Data
FROM read_reg_key(globs='HKEY_USERS/*/Software/Microsoft/Windows/CurrentVersion/Run*/*')
})
WHERE ValueData =~ '(?i)wscript|cscript|\.js|\.jse|\.vbs'
AND ValueData =~ '(?i)appdata|programdata|temp|downloads'
Note: adapt the registry glob to your Velociraptor version — Windows.Registry.Hunter or the Windows.Sys.Users + raw registry accessors work well if the inline glob above isn't supported in your deployment.
Remediation & Verification Script
Run this on endpoints flagged by detection logic or listed in victim notifications. It inventories persistence, script-host executions, and suspicious JS artifacts, and produces a triage report.
# Gootloader triage and verification script - run elevated
$report = "$env:TEMP\gootloader_triage_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
"=== Gootloader Triage Report - $env:COMPUTERNAME ===" | Out-File $report
# 1. Audit Run/RunOnce keys for script-based persistence
"`n[+] Run Key Persistence Entries:`n" | Out-File $report -Append
$runPaths = @(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run'
)
foreach ($path in $runPaths) {
if (Test-Path $path) {
(Get-ItemProperty $path).PSObject.Properties |
Where-Object { $_.Value -match '\.js|\.jse|\.vbs|wscript|cscript' -and $_.Name -notmatch '^PS' } |
ForEach-Object { "$path :: $($_.Name) = $($_.Value)" | Out-File $report -Append }
}
}
# 2. Find JavaScript files in user-writable staging paths (last 90 days)
"`n[+] Suspicious JS files in AppData/Temp/Downloads (last 90 days):`n" | Out-File $report -Append
$cutoff = (Get-Date).AddDays(-90)
Get-ChildItem -Path "$env:APPDATA","$env:LOCALAPPDATA\Temp","$env:USERPROFILE\Downloads","C:\ProgramData" `
-Recurse -Include *.js,*.jse -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt $cutoff } |
Select-Object FullName, Length, LastWriteTime |
Out-File $report -Append
# 3. Scheduled tasks invoking script interpreters or scripts
"`n[+] Scheduled tasks referencing scripts:`n" | Out-File $report -Append
Get-ScheduledTask | ForEach-Object {
$actions = $_.Actions | Out-String
if ($actions -match 'wscript|cscript|powershell.*\.js|\.jse') {
"$($_.TaskPath)$($_.TaskName) :: $actions" | Out-File $report -Append
}
}
# 4. Verify script-host hardening status (recommended: disable WSH for standard users via GPO)
"`n[+] WSH status (0 = disabled, recommended for non-admin endpoints):`n" | Out-File $report -Append
$wsh = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings' -Name Enabled -ErrorAction SilentlyContinue
if ($wsh) { "WSH Enabled = $($wsh.Enabled)" | Out-File $report -Append } else { "WSH setting not configured (default: enabled)" | Out-File $report -Append }
Write-Host "Triage complete. Report: $report"
Remediation
- Identify infected endpoints immediately. If the FBI/DOJ victim notification reaches you (directly or via your ISP/CERT), treat it as a confirmed incident, not an alert. Cross-reference against your own telemetry using the hunts above — notifications lag reality.
- Isolate before you clean. Gootloader infections correlate strongly with ransomware staging. Assume follow-on access (Cobalt Strike, SystemBC, credential theft) until proven otherwise. Isolate the host, capture memory if DFIR capability exists, then reimage. Gootloader's in-memory staging means artifacts may be sparse — memory capture is valuable.
- Hunt laterally. Loader infections on one endpoint justify a fleet-wide sweep for the TTPs above: wscript-spawned PowerShell, Run-key script persistence, JS in user paths. The 25,000-infection figure means operators had volume access — check for other initial access in the same window.
- Reset credentials for affected users and hosts. Assume any credentials typed, cached, or stored on an infected machine are compromised. Include service accounts and local admin passwords via LAPS rotation.
- Neutralize the delivery vector.
- Block or restrict
.js/.jseexecution by standard users. Change the default file association for script files from WSH to Notepad via GPO — this single control kills the double-click execution chain. - Consider disabling Windows Script Host entirely (
HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings\Enabled = 0) for endpoints whose users don't legitimately run scripts. - Configure proxy/DNS controls to flag ZIP downloads containing script files from low-reputation domains, and alert on search-referred downloads of archives containing
.js.
- Block or restrict
- Block seized and sinkholed domains at your resolver anyway — seized domains have historically been transferred, expired, or re-registered. Add them to your blocklists rather than assuming law enforcement custody is permanent.
- Monitor for rebuild. Qakbot and Emotet both returned after takedowns. Keep the detections in this post active; Gootloader operators or their customers have demonstrated reconstitution capability. Expect the SEO-poisoning vector to survive even if this specific infrastructure does not.
- User awareness, targeted. Gootloader victims were searching for business templates. Brief your users — especially legal, finance, and HR — that search results for document templates are an active malware delivery channel. This is a more effective control than generic phishing training for this specific threat.
Related Resources
Security Arsenal Incident Response Services AlertMonitor Platform Book a SOC Assessment incident-response Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.