Windows Defender Application Control (WDAC) Updates in 20H2 and Building a Simple, Secure Windows-only Policy

Latest Improvements to WDAC in 20H2

Before diving into the weeds, I wanted to highlight the improvements to WDAC in 20H2 that I observed.

  1. There are no longer SKU licensing restrictions when building WDAC policies. Previously, one needed Window 10 Enterprise or Education to configure and build WDAC policies. This restriction has since been lifted. The policy described below was built and deployed on a Windows 10 Professional host.
  2. The CodeIntegrity event log no longer appears to be polluted with NGEN events — i.e. system .NET assemblies otherwise permitted by policy that cease to retain their signature upon being converted into a native image. Previously, these events always served as a nuisance and needed to be filtered accordingly while also consuming unnecessary log space.
  3. Since Windows version 2004, driver signing practices now finally appear to be more stringently enforced, permitting “EV Signers” and “WHQL” enforcement on at least 1st-party Microsoft hardware now. Ever since owning Microsoft hardware, I was always under the assumption that 1st-party Microsoft drivers would be properly signed, permitting the far more secure driver enforcement WDAC configuration that enforces all drivers permitted to load per policy to be WHQL and EV-signed. For the longest time, there was always a handful of drivers that prevented this configuration but at least on a fully-updated Surface Gen. 1 Laptop, this is no longer the case. From this point forward, there is no excuse for a driver to not be signed in accordance with WHQL certification requirements.

My WDAC Policy Objective

Build a secure, Windows-only policy that just works.

  • “Secure”: When I refer to secure, I am referring to a policy that is not overly permissive and wouldn’t present any immediately obvious bypasses. I would prefer that my policy not have any rules that would implicitly permit execution of something outside the scope of the policy, in this case, “Windows-only.” For example, if at all possible, I always try to avoid FilePath rules as those can be prone to introducing unintentional bypasses if an attacker is able to drop an executable or script into a permitted directory.
  • I want a policy that will only execute Windows-signed and Microsoft Store-signed code. This laptop I’m building is for my young daughter where at this point in her life, she currently has no need to execute anything outside of the Microsoft ecosystem. “Windows-signed” is distinguished from “Microsoft-signed” code in that I am referring to Microsoft-signed code that is signed with a special certificate used only for code included by default with the operating system (and in relevant update code as well). On a technical level, Windows-signed code is identified by a Microsoft signature (yes, there’s nuance in what defines a truly legitimate Microsoft signature) where the certificate has a special enhanced key usage (EKU) attribute of Fortunately, WDAC is unique in its ability to build allowlist logic from certificate EKUs. Additionally, knowledge of certificate minutiae is unnecessary as Microsoft supplies a default, Windows-only policy template out of the box. The point here is to be knowledgeable of the distinction between Windows-signed and Microsoft-signed code. For example, Sysinternals, because it is not an in-box utility is Microsoft-signed, not Windows-signed.
  • “Just works”: In other words, I want the absolute minimum maintenance burden for this policy. The laptop must run Windows and Store-signed code, block known bypasses, and update without issue. In theory, the only occasional maintenance that should be required will be to occasionally update block rules covering new WDAC bypasses in Windows-signed code.

Laptop Specifications

When working with WDAC, it is important to consider not only the software you intend to permit but to also be mindful of its hardware since that can affect both kernel and user-mode rules for 3rd-party drivers and relevant, accompanying software.

  • Laptop: Microsoft Surface Gen. 1 Laptop
  • Operating System: Windows 10 Professional 20H2
  • Account: My daughter’s account will be a standard, non-admin user. I will maintain an admin account that will only be used to perform maintenance and build/deploy WDAC policy.

Building and Deploying a Custom Windows-only Policy

For this simple policy, I modified and then merged two separate policies:

  1. The DefaultWindows_Audit.xml template policy located in C:\Windows\schemas\CodeIntegrity\ExamplePolicies. I copy and rename this policy as BasePolicyWindows.xml in this post.
  2. The Microsoft recommended block rules that will serve to prevent execution of Windows-signed executables that can be used to circumvent code integrity enforcement. I name this policy UserBlockRules.xml in this post. Microsoft also supplies a set of driver block rules but these are unnecessary for this use case since we will only permit Microsoft-signed drivers to load.
  3. I then merge the above two policies and name the merged policy Merged.xml prior to deployment.
  1. I added the “Disabled:Flight Signing” rule. I have no intention to run Windows Insider Preview (WIP) builds, therefore flight-signed code (i.e. code specially signed for WIP builds) should not be permitted to execute.
  2. I added the “Required:EV Signers” and “Required:WHQL” rules. Again, from Windows version 2004 moving forward, there should be no reason that drivers are not EV and WHQL signed.
  3. I removed all signer rules that would permit flight-signed code to execute. Even with the “Disabled:Flight Signing” rule enabled, there is no reason for the signer rules to remain in the policy. The philosophy I strive to apply is that rules should only be present in my policy that I explicitly want to allow or deny.
  4. I removed test root signer rules. Again, I have no need to permit the execution of test-signed code so the rules should not be present in my policy.
  5. Finally, after performing auditing, I will remove the “Enabled:Audit Mode” rule, placing my policy into enforcement mode.
  1. I removed all the policy rules. Since I will merge these rules into a base policy, I like to minimize confusion by maintaining policy rules in a single base policy, BasePolicyWindows.xml in this case.


My hope is that any security practitioner who is comfortable with Windows at least experiment with WDAC. As a defender who’s professional work involves helping to develop detection logic for attack technique after attack technique, I sometimes feel defeated at the notion and expectation that every attack technique should be detected, a reality that is far from realistic or achievable in many cases. Knowing what I know about the strength of WDAC enforcement, I have direct experience in working within a reality where the majority of attack techniques are almost completely mitigated by enforcing code integrity.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store