1736 words
9 minutes
A Field Guide to WDAC Bypass Techniques

A Field Guide to WDAC Bypass Techniques#

Windows Defender Application Control (WDAC) — now rebranded by Microsoft as Application Control / Application Control for Business — is one of the strongest code-integrity controls on a modern Windows estate. It decides what code is allowed to run, and it does so in the kernel, early, and with a policy model that scales from “trust everything Microsoft-signed” up to a tightly curated allow-list. When deployed well, it shrinks an attacker’s options dramatically.

So naturally there is a decade of public research on how to get around it.

This post is a tour of that landscape. It is organised by mechanism rather than by binary, because the mechanisms recur: a signed scripting engine, a debugger that controls execution, a compiler that turns data into code, a COM/XSL pipeline that interprets a markup format. Once you know the handful of shapes a WDAC bypass takes, a new “0day” LOLBin is usually an old shape wearing a new filename. For the exhaustive, maintained catalogue of documented techniques, the canonical resource is Jimmy Bayne’s UltimateWDACBypassList; this article is a companion orientation, not a substitute.

Table of Contents#

  1. Why WDAC Bypass Research Exists
  2. The Trust Model, in One Paragraph
  3. Mechanism 1 — Debuggers
  4. Mechanism 2 — Compilers and Scripting Hosts
  5. Mechanism 3 — Signed Installers and Utilities
  6. Mechanism 4 — COM, XSL, and the Scripting Engines
  7. Mechanism 5 — Windows Subsystem for Linux
  8. Mechanism 6 — Novel Exploitation (BYOVA, Browser, Catalog Hygiene)
  9. Why Block Lists Are Reactive
  10. Building and Testing Policies
  11. The Wider Lesson
  12. References

1. Why WDAC Bypass Research Exists#

Application control is a deny-by-default control built on top of code signing. The unstated assumption is that signed binaries only do what their signed purpose says they do. That assumption is false in a useful way: a great many Microsoft-signed binaries are, by design, interpreters, compilers, debuggers, or extensibility hosts. They take instructions from a data file, a script, a project manifest, a stylesheet, or a debugger script — and they execute them. If the trusted binary is allowed to run, and it will faithfully execute attacker-supplied logic, then WDAC has authorised the execution by proxy.

That is the whole game. Every technique below is a search for trusted binaries whose legitimate function is “run arbitrary logic,” followed by working out how to feed them that logic without tripping the policy.

2. The Trust Model, in One Paragraph#

A WDAC policy is an XML document compiled into a binary code-integrity policy (.cip) that the kernel’s Code Integrity component enforces at image-load time. Trust is granted by rules: signer/publisher rules (a certificate chain plus a partial leaf hash), path rules, hash rules, and checks for WHQL signing, specific EKUs, or a recognised Windows root. Most enterprise policies carry implicit trust for the Microsoft signing ecosystem — which is precisely why Microsoft-signed developer tooling is such fertile ground. UMCI (User-Mode Code Integrity) extends the same idea to script engines and is where much of the PowerShell/COM research lives.

3. Mechanism 1 — Debuggers#

A debugger is the most direct primitive of all: it controls register state and execution flow, which means it controls what code runs.WDAC evaluates at image load, not at “is a signed process manipulating another process’s memory,” so a signed debugger that manipulates an already-running, already-trusted process flies under the policy.

BinaryMechanism (original summary)Original research
cdb.exeConsole debugger runs shellcode from a script via .script/memory-write primitivesMatt Graeber — WinDbg/CDB as a Shellcode Runner
windbg.exeSame debugger scripting surface as CDBMatt Graeber — WinDbg/CDB as a Shellcode Runner
dbgsrv.exeDebugger server used to attach and drive code execution remotelyCasey Smith / Ross Wolf — How to Bypass WDAC with dbgsrv.exe (FortyNorth)
WinDbgX.exeStore-distributed, Microsoft-signed WinDbg Preview; outside the recommended block list; injects shellcode via .wds scriptingCerberSec — Bypass WDAC WinDbg Preview (see my write-up)

A cluster of debugger-family binaries (kd.exe, ntkd.exe, ntsd.exe, dbgsvc.exe) also appear on Microsoft’s block list even where public abuse write-ups are thin — the mechanism is the same and the block is precautionary.

4. Mechanism 2 — Compilers and Scripting Hosts#

Compilers and REPL hosts are trusted programs whose job is to consume source and emit — or directly execute — code. If the host is signed and allowed, and the source lives in a data file the policy doesn’t evaluate, you have execution.

Binary / familyMechanism (original summary)Original research
msbuild.exeCompiles and executes inline C#/VB tasks from a project fileCasey Smith — Bypassing Application Whitelisting using MSBuild.exe
csi.exe / rcsi.exeRoslyn C# interactive REPL runs C# scriptsCasey Smith — CSI.EXE; Matt Nelson — RCSI.EXE
dnx.exe.NET execution environment runs project codeMatt Nelson — Bypassing AWL by using DNX.EXE
dotnet.exe.NET Core CLI runs assemblies/commandsJimmy Bayn — DotNet Core: A Vector for AWL Bypass
fsi.exe / fsiAnyCpu.exeF# interactive host executes F# inlineNick Tyrer / Jimmy Bayn — Wfc.exe, Fsi.exe, FsiAnyCpu.exe
wfc.exeF# workflow compilerJimmy Bayn — same write-up
dbghost.exeVisual Studio T4 template host executes template logicCasey Smith — Ghost And The Darkness

The pattern is identical across all of them: find the signed host, hand it a data file containing your logic, let it execute on your behalf.

5. Mechanism 3 — Signed Installers and Utilities#

A second class is signed Microsoft binaries that load or process attacker-controlled content during legitimate operations — installers, helpers, and UI-automation tools that can be coerced into running arbitrary code, usually through deserialisation, custom-script hooks, or by design exposing a “run this” capability.

BinaryMechanism (original summary)Original research
InstallUtil.exeInstaller host loads and invokes attacker assembly methodsJames Forshaw — Abusing InstallUtil
addinutil.exeInsecure deserialization of add-in config@McKinleyMike / @TheLatteri — Insecure Deserialization in AddinUtil.exe
runscripthelper.exeSigned utility executes PowerShell from a constrained pathMatt Graeber — Bypassing AWL with runscripthelper.exe
visualuiaverifynative.exeUI-automation verifier loads and runs codeLee Christensen / Jimmy Bayn — VisualUiaVerifyNative
bginfo.exeSysinternals tool runs embedded VBScriptOddvar Moe — Bypassing AWL with BGInfo
infdefaultinstall.exeINF-based installer runs an installer sectionKyle Hanslovan / Chris Bisnett — Evading Autoruns
Microsoft.Workflow.Compiler.exeWorkflow compiler deserialises and runs logicMatt Graeber — Arbitrary Unsigned Code Execution Vector

6. Mechanism 4 — COM, XSL, and the Scripting Engines#

UMCI extends code integrity into script-engine territory, so the bypass research here is dense. The recurring idea: a trusted scripting engine or COM component interprets a format (XSL, VBS, CHM, XML manifest) that carries executable content.

  • WMIC stylesheetswmic.exe honours an /format: flag pointing at an XSL stylesheet; the stylesheet runs script. Casey Smith documented the original. (WMIC Whitelisting Bypass)
  • COM XSL transformation (CVE-2018-8492) — the same XSL idea through COM instantiation, defeating several application-control products. Jimmy Bayn’s write-up is the reference. (COM XSL Transformation)
  • winrm.vbs — a signed script host abused for execution. Matt Graeber’s write-up is canonical. (Arbitrary Unsigned Code Execution in winrm.vbs)
  • CHM (CVE-2017-8625) — HTML Help as a UMCI bypass. Oddvar Moe and Matt Nelson.
  • WSH / mshtamshta.exe and the Windows Script Host remain evergreen primitives for executing script content from a trusted host.
  • PowerShell CLM/UMCI CVEs — a long tail of Constrained Language Mode escapes (CVE-2017-0215, CVE-2017-0007, CVE-2017-8715, CVE-2018-8212, Invoke-History) where the scripting engine itself could be coaxed out of restricted mode.
  • Catalog hygiene — abusing the way signature catalogs are trusted to launder unsigned code as if it were signed. (Abusing Catalog Hygiene)

7. Mechanism 5 — Windows Subsystem for Linux#

The WSL family (bash.exe, wsl.exe, lxrun.exe, wslconfig.exe, wslhost.exe) exposes a Linux world that can be used to run code outside the constraints a Windows-only policy assumed. Alex Ionescu’s lxss research is the foundational write-up. The defensive lesson: a policy scoped to Windows binaries is not scoped to everything that runs on Windows.

8. Mechanism 6 — Novel Exploitation (BYOVA, Browser, Catalog Hygiene)#

Not every bypass is a LOLBin. Some are genuine vulnerabilities or operational tradecraft:

  • Browser exploits — a memory-corruption exploit in an allowed browser achieves execution that WDAC then has to permit because the browser is trusted. Valentina Palmiotti’s Operationalizing browser exploits to bypass WDAC (IBM X-Force) is the clearest treatment.
  • Electron/Node.js apps — a signed Electron shell (e.g., a C2 like Loki) executes JavaScript payloads; WDAC trusts the shell. Bobby Cooke’s Bypassing WDAC with Loki C2 (IBM X-Force) documents the pattern.
  • Bring-Your-Own-Vulnerable-Application — bring a signed-but-vulnerable binary and exploit it for unsigned execution.

9. Why Block Lists Are Reactive#

Microsoft maintains a recommended block list (formerly the “Applications that can bypass WDAC” list) that denies the most abused LOLBins. It is a defensive essential — but it is structurally reactive. A new signed primitive (the Store-distributed WinDbg Preview being the recent textbook case) is not on the list until someone publishes it, and a determined defender ends up playing whack-a-mole against the next interpreter Microsoft ships.

Two practical corollaries:

  1. When you apply the recommended block-rules policy, strip the default-allow rules. The block list ships with two default-allow file rules (ID_ALLOW_A_1, ID_ALLOW_A_2) that must be removed, or the “block” policy still allows more than you intend.
  2. A signed-binary block list cannot, by construction, anticipate signed binaries whose legitimate function is to run code. Pair it with behavioural detection, least privilege, and network segmentation.

10. Building and Testing Policies#

The defensive toolkit is mature and worth knowing whether you are red or blue:

Always validate in audit mode first, then promote to enforced once your event log is quiet. A policy that breaks the business is a policy that gets turned off.

11. The Wider Lesson#

Catalogues like the UltimateWDACBypassList are not vulnerability databases — they are an inventory of the tension at the heart of application control: you cannot whitelist “programs that run code” without whitelisting code running. Every compiler, debugger, scripting host, and COM interpreter that carries a Microsoft signature is, from the policy’s point of view, a trusted general-purpose execution engine. The defensive answer is therefore not a perfect block list (there is no such thing) but defence in depth — application control as one layer, with behavioural detection, least privilege, identity controls, and segmentation behind it.

For attackers and red teamers, the lesson is the mirror image: stop looking for “new” bypasses and start looking for trusted binaries whose job is to interpret something. The shapes are few; the filenames are many.


12. References#

A Field Guide to WDAC Bypass Techniques
https://mranv.pages.dev/posts/wdac-bypass-landscape-field-guide/
Author
Anubhav Gain
Published at
2026-07-13
License
CC BY-NC-SA 4.0