§ AT

ClickFix Detection Has a RunMRU Blind Spot, and FileFix Is Walking Through It

The thing that makes ClickFix hard to catch isn’t the payload at the end of the chain. It’s that nothing earlier in the chain looks like an attack. A user lands on a page that tells them to press Win+R, paste, and hit Enter to “verify” they’re human or to “fix” a rendering error. They do it. To the endpoint, a person opened the Run dialog and typed a command, which is precisely what the Run dialog exists for. By the time PowerShell reaches out for a second stage, the social engineering has already worked, and your EDR is staring at a process tree rooted in explorer.exe doing something explorer.exe is allowed to do.

That benign surface is the whole point, and it has paid off. Per The Hacker News, ClickFix accounted for 47% of the attacks Microsoft observed over the past year. It has also commoditized: builder kits go for roughly $200 to $1,500 a month on forums, which is why the lure pages all look the same and the command patterns rhyme across unrelated intrusions.

Most shops write their first ClickFix detection against the Windows Run dialog. It’s the right place to start. It is also, by 2026, the place attackers have already started routing around. So this is less “here is a detection” and more “here is what your detection misses the day after you ship it.”

The mechanism, minus the parts you don’t need

The lure poisons the clipboard from the browser. JavaScript on the page writes the real command into the clipboard buffer; what gets rendered in the visible field is a decoy \u2014 a fake “verification” comment line padded with enough whitespace that the actual command scrolls off to the right where nobody looks. The user pastes the whole thing and sees only the reassuring part. That decoy text is itself a forensic gift, which I’ll come back to.

The executed command leans on living-off-the-land binaries: powershell, mshta, rundll32, wscript, curl, msiexec. PowerShell stays the favorite, usually carrying iwr/irm/iex, a DownloadString/DownloadFile, base64 via FromBase64String, and a hidden window flag. First stages tend to come off direct IPs, CDN domains, paste sites, or junk TLDs (.live, .shop, .icu), frequently behind a Bitly-style shortener and sometimes with a media extension bolted on to hide intent.

A more recent wrinkle worth knowing about: instead of calling PowerShell directly, some chains now route through SyncAppvPublishingServer.vbs, a signed Microsoft App-V script, to proxy execution through a trusted component. Blackpoint researchers documented this delivering the Amatera stealer. The reason it matters to a defender is narrow but real. It puts a signed, Microsoft-shipped intermediary between the Run dialog and the eventual script interpreter, which is exactly the seam a naive “explorer.exe spawned powershell.exe” rule falls into.

The detection everyone writes first

When a command runs from the Run dialog, Windows records it. The artifact lives at HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU, written by explorer.exe, with values stored as a, b, c and so on, each suffixed with \1 and ordered by the MRUList value. It only writes on successful launch, which means a failed paste leaves nothing. Keep that in mind during an investigation where the user swears they ran something.

In Defender XDR the query keys on DeviceRegistryEvents where ActionType == "RegistryValueSet", InitiatingProcessFileName == "explorer.exe", and RegistryKey has "\CurrentVersion\Explorer\RunMRU". From there you’re matching on the contents. Two filters carry most of the weight. The first is the literal decoy text: Microsoft’s own published hunt looks for the \u2705 check-mark glyph and the “I am not a robot / Verification ID” phrasing the lure pastes along with the command. The second is more durable: a regex for Cyrillic, Greek, Hebrew, Arabic, Thai and similar code-point ranges sitting next to a LOLBin name, because operators pad commands with foreign-script characters to break naive string matching. If you see powershell adjacent to a block of Cyrillic in a RunMRU value, that is not a sysadmin.

One thing to whitelist immediately: a RunMRU value of mshta\1 or mshta.exe\1 with nothing else is the benign “user opened mshta” entry, not an attack. Microsoft’s query explicitly excludes it. If you don’t, you’ll chase ghosts.

If you’re on Sysmon rather than Defender, this is registry Event ID 13 (RegistryValueSet). The catch: plenty of Sysmon configs, including some widely copied community baselines, don’t enumerate RunMRU in their registry section at all. Open your active config and grep the <RegistryEvent> block for RunMRU before you assume the events are in your index. If they aren’t, your “ClickFix detection” is matching on data you never collected. (This is the kind of gap that sits quiet for months because the rule validates fine in a lab where someone manually added the key.)

…and where it goes blind the next day

FileFix.

Same playbook, different input surface. Instead of the Run dialog, the lure tells the user to paste into the File Explorer address bar (Ctrl+L), presenting the command as a file path. The researcher mr.d0x is generally credited with the public technique, and it has been observed in the wild delivering stealers. Here’s the operational consequence: pasting into the address bar does not write RunMRU. Your registry detection, the one you just tuned, sees nothing. The variants kept coming after that \u2014 FileFix, JackFix, CrashFix, and others \u2014 and they exist partly because the Run-dialog artifact got too well known.

So a RunMRU-only posture has a blind spot you can drive a stealer through. The fix is a second, complementary detection on process lineage rather than registry writes: a script interpreter or LOLBin (powershell.exe, mshta.exe, cmd.exe, wscript.exe) launched with a parent of explorer.exe, filtered down by command-line indicators \u2014 encoded blobs, -w hidden, the download cmdlets, FromBase64String. On Sysmon this is Event ID 1 (ProcessCreate), which gives you the parent-child relationship and full command line in one event and is the more reliable foundation for lineage hunting than reconstructing trees from registry telemetry. There’s a public Sigma rule on detection.fyi that covers both the Run-dialog and address-bar paths under one logic; it’s a reasonable starting template if you don’t want to write the boolean soup yourself.

The App-V proxy complicates even that. When execution routes through SyncAppvPublishingServer.vbs, the immediate parent of PowerShell may be wscript.exe or the signed script host, not explorer.exe directly, so a rule pinned strictly to explorer.exe \u2192 powershell.exe can miss it. If your EDR exposes the full parent process tree (Defender does, most do now), walk up two or three levels and alert when an explorer.exe-rooted tree contains a script interpreter a couple of hops down, regardless of the immediate parent. Costs you some query complexity. Buys back the coverage.

And note one residual gap that neither detection closes cleanly: a lure that gets the browser itself to spawn mshta.exe or a protocol handler directly never touches the Run dialog or an explorer.exe-rooted tree, so it evades both the RunMRU and the explorer-lineage rules. That’s a separate hunt rooted in browser-process parentage, and worth keeping on the backlog.

Volume, false positives, and the first week

The process-lineage rule is where the noise lives. explorer.exe spawning powershell.exe is genuinely common in developer and admin populations \u2014 people paste one-liners into Run all day. Run that rule unfiltered across a dev-heavy org and the SOC will drown in week one. The command-line indicators are what make it survivable: an interactive admin typing powershell to open a console doesn’t carry a base64 blob and a hidden-window flag. Tune toward the combination of explorer.exe lineage plus download/encode indicators, not the lineage alone.

Expect the false positives to cluster in a few predictable places, and note what they have in common \u2014 they actually carry an explorer.exe parent. Interactive IT remediation one-liners that legitimately use iwr, scripts launched from a desktop or Start-menu shortcut, and the occasional packaged app that shells out on first run from a user-launched process are the realistic offenders. (Pure background machinery \u2014 deployment agents, login scripts, scheduled tasks \u2014 generally parents under svchost.exe, services.exe, or msiexec.exe, not explorer.exe, so a tight lineage rule shouldn’t see most of it.) Carve out the genuine hits by signer, path, or known command hash rather than by suppressing the whole rule. The decoy-text detection, by contrast, is close to zero false positive \u2014 almost nothing benign pastes a check-mark glyph and “Verification ID” into RunMRU \u2014 so weight your alerting and your analyst attention accordingly. Catch on registry where you can (cheap, precise), fall back to lineage where you must (noisier, broader).

Retention math matters here too. In Microsoft Defender XDR, registry-set events are high-volume on a busy fleet; if you’re paying to keep all of DeviceRegistryEvents hot for 90 days you’ll feel it. A reasonable compromise is to keep only the RunMRU subset hot \u2014 via a scheduled summary rule or a filtered export to a cheaper tier \u2014 and age the rest to cold storage, since the RunMRU writes are what you actually hunt against.

What actually reduces it

ClickFix is the rare case where AT \u2014 Awareness and Training \u2014 is load-bearing rather than a checkbox, because the user is the execution engine. “Never paste anything into Run or the File Explorer address bar that a web page told you to copy” is a concrete, teachable rule, unlike most phishing advice. It won’t hit zero. It moves the number.

On the technical side, the durable controls are configuration ones:

Control area Action The catch
CM PowerShell Constrained Language Mode via WDAC/AppLocker Blocks the download-and-exec cradle, but breaks legitimate admin scripting if scoped too wide; pilot on standard-user OUs first
CM Disable or remove mshta.exe Deprecated by Microsoft anyway; check for legacy line-of-business HTAs before pulling it
CM Remove the Run dialog (NoRun GPO) Kills the Run-dialog vector outright; does nothing for FileFix and annoys power users (judgment call per OU)
SC Egress filtering and URL/DNS filtering on first-stage retrieval Catches the second stage even when execution succeeds; junk TLDs and paste sites are reasonable block candidates
SI The RunMRU and process-lineage detections above Registry path is blind to FileFix; you need both
AC / IA Session-token theft response for the credential-stealing variants The Facebook-creator campaigns exfiltrate browser cookies for account takeover; token revocation, not password reset, is the containment

The control-area codes follow the NIST SP 800-53 families: CM = Configuration Management, SC = System and Communications Protection, SI = System and Information Integrity, AC = Access Control, IA = Identification and Authentication.

NoRun is the one people reach for and then regret. It stops Run-dialog ClickFix cleanly, but FileFix walks straight past it through the address bar, and you’ve now generated a helpdesk queue. I’d put Constrained Language Mode and egress filtering ahead of it; they degrade more attack paths and break fewer workflows.

The honest position is that ClickFix is mostly a detection-and-response problem, not a prevention one, because the attack is built out of legitimate user actions and signed binaries \u2014 the configuration controls above are necessary but not sufficient. You will not configuration-manage your way to zero. Watch RunMRU, watch the lineage that RunMRU can’t see, and assume the variant you tuned against last month already has a successor that uses a different input box.

Sources