ClickFix Detection Without the Fairy Tale
ClickFix — the social-engineering pattern where a phony Cloudflare/captcha/MS-Teams page convinces the user to press Win+R, paste a command, and hit Enter — has been the dominant initial-access workflow for commodity loaders since roughly mid-2024. By late 2025 it had eaten most of the macro-document share that survived the MOTW changes, and the variant tree is now broad enough that vendor write-ups disagree on what to call the same loader. The detection problem, though, has not actually changed much. The mechanic is narrow. The telemetry is loud. And yet most SOCs I read detection content from are still writing rules that fire on powershell.exe -enc and calling it a day.
That rule will catch a freshman red-teamer. It will not catch what’s actually landing in inboxes this quarter.
What the chain looks like in the index
The load-bearing piece of ClickFix is not the PowerShell. It is the user typing into the Run dialog. That action writes to HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU, then spawns the command as a child of explorer.exe — not of a browser, not of Outlook, not of any process the user had focus on five seconds earlier. Sysmon EID 1 captures this cleanly if you are collecting it; if you are leaning on the native 4688 with command-line auditing enabled, you get the parent process but you have to join against registry writes to get the RunMRU signal, and on Windows 11 24H2 the registry event timing drifts about 200–400ms behind the process create, which matters when you are building a sequence rule.
The pasted command itself is where the variant zoo lives. Common shapes through 2025 and into early 2026:
mshtafetching a remote.hta(the OG, still works, still common against unmanaged endpoints)powershellwith aiex (irm ...)one-liner, sometimes wrapped incmd /c start /minconhost --headless powershell ...— this one is newer and worth a dedicated rule because legitimate use ofconhost --headlessoutside of WSL and a handful of dev tools is close to zerocurl.exeto a.txtpiped throughcmd, exploiting the fact that a lot of EDR command-line parsers still mishandle the redirectionmsiexec /i http://...against an SMB-or-HTTP-hosted MSI, which is the variant that bypasses the most AppLocker policies I have seen in the wild documented
The last one is the nastiest. msiexec from explorer.exe with an HTTP URL on the command line is essentially never benign on a managed endpoint, and yet half the rule packs I’ve reviewed don’t have a clean detection for it because the authors were focused on PowerShell.
The actual detection, and what it looks like at volume
The rule that earns its keep is a parent-child + command-line + RunMRU correlation, not a string match. Splunk-flavored, against a Sysmon index:
index=sysmon EventCode=1 ParentImage="*\\explorer.exe"
(Image="*\\powershell.exe" OR Image="*\\pwsh.exe" OR Image="*\\mshta.exe"
OR Image="*\\msiexec.exe" OR Image="*\\conhost.exe" OR Image="*\\curl.exe"
OR Image="*\\cmd.exe")
CommandLine IN ("*http*", "*\\\\*", "*iex*", "*Invoke-*", "*--headless*", "*FromBase64*")
| join type=inner host User _time [
search index=sysmon EventCode=13 TargetObject="*\\RunMRU\\*"
| eval _time=_time
]
| where abs(_time - registry_time) < 5
That < 5 second window is where the rule lives or dies. Set it too tight and you miss the cases where the user fumbles the paste and re-opens Run; set it too wide and you start correlating against the sysadmin who hit Win+R three minutes ago to launch services.msc and then independently spawned a PowerShell from a Start menu pin. Five seconds is the value most teams land on after the first tuning pass. Some shops go to seven on laptops with slow disks.
Volume: on a 2,000-endpoint enterprise estate with normal knowledge-worker usage, expect this rule to produce somewhere in the range of 5–25 alerts a day before tuning, and 0–3 after. The top of the noise distribution is usually:
- IT helpdesk scripts the user was told to paste during a remote session. These look identical to ClickFix from the host’s perspective, because they are mechanically the same thing. The only differentiator is the URL or the script content, and on day one you do not have a clean allowlist for either.
- Power users with
cmd /cin their RunMRU history launching internal tools over SMB. Real, recurring, and the right answer is per-user suppression keyed on a hash of the command line, not a blanket allowlist. - Developers using
conhost --headlessfor legitimate WSL/dev-container workflows. Carve these out by user group, not by host.
The IT helpdesk case is the one that bites people. If your service desk’s standard remediation for any complicated ticket is “copy this into Run and press enter,” you have built a control environment where the user cannot distinguish your legitimate workflow from the attacker’s. That is not a detection problem. Detection cannot fix it. Stop doing it.
What the loader does next, and why you want a second-stage rule
The first-stage detection above is high-signal but it has a known blind spot: if the user pasted the command and the network egress was blocked, the command-line still fired but no payload landed. You will get an alert with no follow-on telemetry and the analyst will close it as unresolved. This is fine — actually good, the control worked — but it generates ticket churn.
The second-stage rule is what tells you the loader actually executed. Watch for the explorer-spawned process making an outbound HTTP(S) connection within 30 seconds, OR writing a file under %APPDATA%\Roaming\ or %LOCALAPPDATA%\Temp\ with an executable extension or a .lnk, OR spawning a child that does either of those. Sysmon EID 3 plus EID 11, joined on ProcessGuid. If your EDR exposes the parent process tree natively (Defender for Endpoint does, CrowdStrike does, most others have to be coaxed) you can do this without a join, which is worth a noticeable amount of Splunk license.
This two-stage approach also gives you a cleaner story for the post-incident review: stage-one alert is “user did the thing,” stage-two alert is “the thing worked.” Auditors and IR leads understand both. SI-4(2) — automated tools for real-time analysis — maps neatly onto this if you are writing it up for a control assessor.
Where the rule breaks
A few honest caveats, because every config has a but.
Command-line truncation. Some EDR vendors truncate CommandLine at 1024 or 2048 chars, and the more elaborate ClickFix variants — particularly the ones using padded base64 to defeat AV string matching — push past that. The PowerShell event log (4104, ScriptBlockLogging) catches the deobfuscated form, but only if ScriptBlockLogging is on, and only after the script runs, which means your first-stage rule already fired or already missed. Turn 4104 on, but treat it as confirmation, not detection.
Non-Microsoft shells. Nu, pwsh installed via scoop, anything launched via the Windows Terminal wt.exe wrapper — these can break parent-process assumptions. wt.exe in particular spawns its shell as a child of itself, not of explorer, so the chain looks like explorer -> wt.exe -> pwsh.exe and naive ParentImage="*\explorer.exe" filters miss it. Add wt.exe to the parent allowlist or you will have a gap.
Clipboard-only variants. The newest ClickFix mutation I have seen described in 2026 reports skips the user typing entirely — the malicious page writes a payload to the clipboard via the Clipboard API, then social-engineers the user into hitting Win+V (clipboard history paste) into Run. The RunMRU write still happens. The detection still works. But the threat-intel write-ups that focus on “the user types” miss this, and so do rules built from those write-ups.
And time skew. If your hosts and your SIEM disagree on the wall clock by more than the join window, the correlation rule silently produces nothing. Check this before you debug the rule. I would not bet on every endpoint in a 5,000-host estate being within 5 seconds of true without a working NTP policy and monitoring on the drift, and AU-8 exists for a reason.
Control mapping for the ATO crowd
For anyone writing this up against 800-53:
| Control | How this hits it |
|---|---|
| SI-4(2), SI-4(4) | The detection rule itself; inbound/outbound communications monitoring on stage two |
| SI-3 | Malicious code protection — the loader stage |
| AC-3, AC-6(9) | Least privilege on the workstation prevents most stage-two file writes from succeeding in admin-only paths |
| CM-7(2), CM-7(5) | Application execution policy (AppLocker / WDAC) — the msiexec variant lives or dies here |
| AT-2(3) | User awareness training specifically on paste-and-run, which is the part the user is the last line of defense for and the part most awareness programs still don’t cover specifically |
| AU-8 | Time synchronization, because your correlation rule depends on it |
AT-2(3) is the one I would not skip. The detection is good. The control stack is good. But this is a user-mediated initial access vector, and a thirty-second training video that names the pattern and shows what the fake captcha page looks like meaningfully shifts the click-through rate. Don’t pretend the technical controls alone close it.
What to do Monday
If you have Sysmon EID 1 and EID 13 in your index, write the correlation rule, set the window to five seconds, and accept that the first week is going to be noisy. Carve out the helpdesk’s paste-the-fix workflow — ideally by killing the workflow, not the rule. Add wt.exe to your parent allowlist. Turn on ScriptBlockLogging if it isn’t already. And go look at how your msiexec command-line policy handles HTTP URLs, because that variant is the one that will hurt you the most and the one your existing PowerShell-focused rules will not see.