← All posts

Auditing the MSDT / Follina Attack Surface on Windows

The ms-msdt: URL handler and the scripted-diagnostics engine turned a Word document into remote code execution. Here are the local registry controls that shut Follina (CVE-2022-30190) down - and how WinSentinel checks them.

In May 2022 a security researcher noticed something unusual in a Word document uploaded to VirusTotal: opening it fetched a remote HTML file, and that HTML handed a command line to a program almost nobody thinks about — msdt.exe, the Microsoft Support Diagnostic Tool. No macros. No obvious payload. Just a document that, when previewed, ran attacker code as the user. That was Follina, tracked as CVE-2022-30190, and it worked because two legacy pieces of Windows plumbing were quietly enabled on almost every machine.

How Follina actually worked

The chain hangs on the ms-msdt: URL protocol. Windows registers a handful of custom URL schemes under HKEY_CLASSES_ROOTms-msdt: is the one that launches the diagnostics tool. An Office document can reference an external URL, and that URL can be an ms-msdt: link whose parameters tell MSDT which troubleshooting pack to load and what to run.

MSDT doesn't run script directly — it runs scripted diagnostics: signed PowerShell troubleshooting packs. Follina abused the parameter parsing so that the "troubleshooter" it loaded executed an attacker-supplied command. Two OS features had to be live for the whole thing to fire:

Take either one away and the exploit chain snaps. That's exactly what Microsoft's interim guidance said to do before a patch shipped: delete the ms-msdt URL registration. It's also why hardening this surface matters long after the specific patch — the diagnostics engine is a broad, legacy attack surface, and Follina was one exploit against it, not the last.

The four local controls that shut it down

Every part of this surface is a local registry / policy setting. You don't need EDR or a network sensor to check it — you need to read four keys. WinSentinel's new Diagnostics Hardening audit module reads exactly these and reports a pass/fail with a fix for each.

1. Disable the scripted-diagnostics engine

On hosts that don't rely on the built-in troubleshooters (most servers, most locked-down workstations), turn the engine off entirely:

New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\ScriptedDiagnostics' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\ScriptedDiagnostics' -Name EnableDiagnostics -Type DWord -Value 0

With EnableDiagnostics = 0, MSDT has no engine to drive. This is the single most durable Follina mitigation because it kills the class of attack, not just the one URL trick.

2. Remove the ms-msdt: URL protocol handler

The interim Microsoft workaround. Back the key up first, then delete it:

reg export HKEY_CLASSES_ROOT\ms-msdt "$env:TEMP\ms-msdt-backup.reg" /y
reg delete HKEY_CLASSES_ROOT\ms-msdt /f

Once the protocol is unregistered, a document or link can no longer hand a payload to MSDT through a URL. WinSentinel detects the handler by looking for the URL Protocol marker value on the class root — present means registered, absent means the workaround is in place.

3. Restrict the built-in troubleshooters by policy

Even with the engine off, it's worth blocking users from launching the interactive troubleshooters that invoke MSDT, via the WDI troubleshooting policy:

$k = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WDI\{9c5a40da-b965-4fc3-8781-88dd50a6299d}'
New-Item -Path $k -Force | Out-Null
Set-ItemProperty -Path $k -Name ScenarioExecutionEnabled -Type DWord -Value 0

4. Hold diagnostic data at the minimum floor

The diagnostic-data (telemetry) level isn't part of the exploit, but it governs how much of the diagnostics pipeline stays active and how much data leaves the machine. CIS L1 wants it at Security (0) or Basic (1):

New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Name AllowTelemetry -Type DWord -Value 1

Why a scanner should check this, not a human once

The hard part of Follina-style hardening isn't knowing the fix — it's drift. A feature update re-registers a URL handler. A troubleshooting session flips the engine back on. A new image ships without the policy applied. A one-time manual fix on patch day tells you nothing about the machine six months later.

That's the whole point of turning these into an audit check. WinSentinel reads all four controls on every scan and maps each to a plain pass/warning with a copy-pasteable remediation — so "we mitigated Follina" becomes a fact you can re-verify on any machine, any day, instead of a memory from 2022.

Run it

The Diagnostics Hardening module ships in the free, open-source WinSentinel CLI — like every single-machine audit, it's unlimited and local-only:

dotnet tool install --global WinSentinel.Cli
winsentinel --audit

Look for the Diagnostics Hardening category in the report. Each finding tells you whether the scripted-diagnostics engine, the ms-msdt: handler, the troubleshooter policy, and the telemetry floor are where they should be — and exactly what to run if they're not.