3598 words
18 minutes
WDAC File Rule Level: WHQL

WDAC File Rule Level: WHQL#

Windows Hardware Quality Lab signing — a Microsoft-operated certification program that tests and cryptographically endorses hardware drivers. The WHQL level in App Control for Business allows files that carry the WHQL Extended Key Usage (EKU) in their signing certificate chain.


Table of Contents#

  1. Overview
  2. What WHQL Is — Background
  3. The WHQL Certification Process
  4. How the WHQL Level Works Technically
  5. The WHQL EKU — OID and Hex Encoding
  6. Certificate Chain / Trust Anatomy
  7. Where in the Evaluation Stack
  8. XML Representation
  9. PowerShell Examples
  10. WHQL vs. Option 02 (Required)
  11. Pros & Cons Table
  12. Attack Resistance Analysis — BYOVD Context
  13. When to Use vs. When to Avoid — Decision Flowchart
  14. Real-World Scenario: End-to-End Sequence
  15. OS Version & Compatibility
  16. Common Mistakes & Gotchas
  17. Summary Table

1. Overview#

The WHQL file rule level in App Control for Business allows the execution of files whose signing certificate chain contains the Windows Hardware Quality Lab EKU (Extended Key Usage). This EKU is placed in certificates issued by Microsoft specifically to drivers and hardware firmware that have passed the Hardware Lab Kit (HLK) test suite and received Microsoft’s certification.

Key characteristics of this level:

  • Primarily for kernel-mode binaries: Drivers (.sys files) and related kernel-mode components are the typical targets. User-mode binaries are rarely WHQL-signed.
  • EKU-based trust: Unlike most other WDAC levels that key off certificate subject names or thumbprints, WHQL trust is determined by the presence of a specific OID in the certificate’s Extended Key Usage extension.
  • Broad by design: Trusts any driver that Microsoft has certified, regardless of which hardware vendor submitted it.
  • Connected to but distinct from Option 02: The policy option Required:WHQL (Rule Option 02) mandates that all kernel drivers be WHQL-certified; the WHQL rule level is a different concept — it’s the trust grant for files that are WHQL-signed.

2. What WHQL Is — Background#

Windows Hardware Quality Lab#

The Windows Hardware Quality Lab (WHQL) program, now operationally known as the Windows Hardware Compatibility Program (WHCP), is Microsoft’s certification framework for hardware drivers and devices. The program:

  1. Defines a test suite (the Hardware Lab Kit, HLK) that driver vendors must run against their hardware
  2. Requires vendors to submit test results to Microsoft through the Windows Hardware Dev Center portal
  3. Issues a WHQL-signed driver package after verifying the test results meet certification requirements

WHQL signing is distinct from standard Authenticode signing. A regular Authenticode certificate (from DigiCert, Sectigo, etc.) allows a vendor to self-sign their driver with their own identity. WHQL signing means Microsoft itself cryptographically endorses the driver using a certificate with the WHQL EKU embedded.

Why WHQL Matters to WDAC#

Before WDAC, the primary kernel-mode trust mechanism was the kernel-mode code signing policy introduced in Windows Vista 64-bit (which required all kernel drivers to be signed). WDAC extends this by allowing organizations to specify which signed drivers they permit.

The WHQL level is the most practical way to allow all properly-certified drivers without enumerating every driver vendor individually. It represents Microsoft’s explicit endorsement: “We tested this driver, it met our quality bar, and we signed it with our WHQL certificate.”


3. The WHQL Certification Process#

sequenceDiagram
participant Vendor as Hardware Vendor
participant HLK as HLK Test Lab (Vendor's)
participant Portal as Windows Hardware Dev Center
participant MSFT as Microsoft WHQL Team
participant Sign as Microsoft Signing Service
participant Driver as WHQL-Signed Driver Package
Vendor->>HLK: Run Hardware Lab Kit test suite against device
HLK-->>Vendor: HLK test results (.hlkx package)
Vendor->>Portal: Submit HLK results via Dev Center portal
Portal->>MSFT: Routes submission for review
MSFT->>MSFT: Verify test results meet WHCP requirements
MSFT->>MSFT: Review driver package integrity
alt Tests Pass
MSFT->>Sign: Approve driver for WHQL signing
Sign->>Sign: Signs driver with Microsoft's WHQL certificate\n(contains WHQL EKU OID 1.3.6.1.4.1.311.10.3.5)
Sign-->>Driver: Returns signed .sys + .inf + catalog file
Driver-->>Vendor: Certified driver package available for download
Note over Driver,Vendor: Driver is now WHQL-certified\nci.dll WHQL EKU check will pass
else Tests Fail
MSFT-->>Vendor: Rejection with failure details
Vendor->>HLK: Fix driver issues, re-test
end

The critical output of this process is a driver package where the .sys file (and associated catalog) carries a signature from Microsoft’s WHQL signing certificate — a certificate that includes the WHQL EKU OID. This is what WDAC’s WHQL level checks for.


4. How the WHQL Level Works Technically#

When ci.dll (the kernel’s Code Integrity component) evaluates a file against a WDAC policy containing WHQL rules, it performs the following checks:

Step 1: Is the file kernel-mode?#

WHQL rules are evaluated in the kernel-mode signing scenario. For user-mode binaries, different rule sets apply. The evaluation context is determined by how the binary is being loaded:

  • Kernel drivers loaded via IoLoadDriver → kernel-mode scenario
  • Executables and DLLs loaded via the process loader → user-mode scenario

Step 2: Does the certificate chain contain the WHQL EKU?#

ci.dll walks the certificate chain from the leaf certificate upward. At each level, it checks the Extended Key Usage extension for the presence of OID 1.3.6.1.4.1.311.10.3.5 (Windows Hardware Driver Verification).

The EKU can appear in:

  • The leaf certificate (most common for WHQL-signed drivers)
  • An intermediate CA certificate (for enterprise CA hierarchies, less common)

Step 3: Does the chain root in a trusted WHQL root?#

Microsoft uses two root CAs for WHQL signing:

  1. Microsoft Product Root 2010 — for drivers signed after 2010
  2. Microsoft Code Verification Root — for older drivers signed under the previous root

The chain must root in one of these Microsoft-operated roots. This prevents third-party CAs from issuing “WHQL-like” certificates.

Step 4: WDAC Policy Rule Match#

If a WHQL Signer rule exists in the policy and the above checks pass, the file is allowed. If no WHQL rule exists, the file evaluation continues to other applicable rules.


5. The WHQL EKU — OID and Hex Encoding#

The WHQL EKU has the following OID:

OID (dotted decimal): 1.3.6.1.4.1.311.10.3.5
OID meaning: Microsoft → Products → OIDs → WHQL-related → Windows Hardware Driver Verification

In WDAC XML, EKUs are represented as hexadecimal DER-encoded OID values. The encoding process:

  1. Start with the OID in dotted decimal: 1.3.6.1.4.1.311.10.3.5
  2. Prepend the ASN.1 OID tag 06 (object identifier)
  3. Encode the OID value per BER/DER OID encoding rules
  4. Express as uppercase hex

The result:

DER-encoded WHQL EKU value: 010A2B0601040182370A0305

Breaking down the hex encoding:

  • 01 — Length byte (context-dependent in WDAC’s encoding format)
  • 0A — Length of the OID content (10 bytes)
  • 2B — Encodes the first two OID components (1.3 → 40×1+3=43=0x2B)
  • 06 01 04 01 82 37 0A 03 05 — Remaining OID components encoded per BER rules
    • 06 = 6
    • 01 = 1
    • 04 = 4
    • 01 = 1
    • 82 37 = 311 (multi-byte encoding: 0x82=high byte flag, 0x37=55 → 311)
    • 0A = 10
    • 03 = 3
    • 05 = 5

In WDAC XML, this appears as:

<EKU ID="ID_EKU_WHQL" Value="010A2B0601040182370A0305" />

6. Certificate Chain / Trust Anatomy#

graph TB
subgraph "WHQL Certificate Chain"
ROOT["Microsoft Product Root 2010\nOR\nMicrosoft Code Verification Root\n(Self-Signed, air-gapped HSM at Microsoft)"]:::root
MSWHQL_CA["Microsoft Windows Hardware\nCompatibility PCA 2021\n(Intermediate CA — WHQL signing)"]:::pca
LEAF["Microsoft Windows Hardware\nCompatibility Publisher\nEKU: 1.3.6.1.4.1.311.10.3.5\n(WHQL EKU present in leaf cert)"]:::pca
DRIVER["nvlddmkm.sys\nNVIDIA Display Adapter Driver\nSigned by Microsoft's WHQL signing service\non behalf of NVIDIA's submission"]:::file
subgraph "EKU Extension in Leaf Cert"
EKU1["Code Signing (1.3.6.1.5.5.7.3.3)"]:::node
EKU2["Windows Hardware Driver Verification\n(1.3.6.1.4.1.311.10.3.5) ← WHQL EKU"]:::allow
end
end
ROOT --> MSWHQL_CA
MSWHQL_CA --> LEAF
LEAF --> DRIVER
LEAF -.->|"contains"| EKU1
LEAF -.->|"contains"| EKU2
classDef root fill:#1a0d2e,stroke:#6b21a8,color:#d8b4fe
classDef pca fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef leaf fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef file fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef node fill:#162032,stroke:#1e3a5f,color:#e2e8f0

Important note on WHQL signing mechanics: Unlike standard Authenticode where the vendor signs their own binary with their own private key, WHQL-signed drivers are signed by Microsoft’s private key (on behalf of the vendor’s submission). The vendor submits the driver to Microsoft’s portal, and Microsoft signs it. This is why WHQL certs chain to Microsoft roots, not to vendor roots.


7. Where in the Evaluation Stack#

flowchart TD
START(["Kernel Driver Load Requested\n(e.g., nvlddmkm.sys)"]):::node
SCENARIO{"Kernel-mode or\nUser-mode context?"}:::node
USER_PATH["User-mode rule evaluation\n(different rule set applies)"]:::node
HASH_CHECK{"Hash rule\nexists for this .sys file?"}:::node
HASH_ALLOW(["ALLOW — Hash match\n(most specific)"]):::allow
FP_CHECK{"FilePublisher/WHQLFilePublisher rule\nexists? (EKU + CN + filename + version)"}:::node
FP_ALLOW(["ALLOW — WHQLFilePublisher match"]):::allow
PUB_CHECK{"Publisher/WHQLPublisher rule\nexists? (EKU + leaf CN)"}:::node
PUB_ALLOW(["ALLOW — WHQLPublisher match"]):::allow
WHQL_CHECK{"WHQL rule exists?\n(EKU OID 1.3.6.1.4.1.311.10.3.5\nin cert chain?)"}:::node
WHQL_ALLOW(["ALLOW — WHQL EKU match\n(any WHQL-certified driver)"]):::allow
PCA_CHECK{"PcaCertificate rule\nexists for signer chain?"}:::node
PCA_ALLOW(["ALLOW — PcaCertificate match"]):::allow
DEFAULT{"Default action?"}:::node
BLOCK(["BLOCK — Kernel driver\nnot authorized"]):::block
AUDIT(["AUDIT LOG — allowed in\naudit mode, blocked in enforce"]):::warn
START --> SCENARIO
SCENARIO -->|"Kernel-mode"| HASH_CHECK
SCENARIO -->|"User-mode"| USER_PATH
HASH_CHECK -->|"Yes"| HASH_ALLOW
HASH_CHECK -->|"No"| FP_CHECK
FP_CHECK -->|"Yes"| FP_ALLOW
FP_CHECK -->|"No"| PUB_CHECK
PUB_CHECK -->|"Yes"| PUB_ALLOW
PUB_CHECK -->|"No"| WHQL_CHECK
WHQL_CHECK -->|"Yes — EKU found in chain"| WHQL_ALLOW
WHQL_CHECK -->|"No"| PCA_CHECK
PCA_CHECK -->|"Yes"| PCA_ALLOW
PCA_CHECK -->|"No"| DEFAULT
DEFAULT -->|"DefaultDeny"| BLOCK
DEFAULT -->|"Audit mode"| AUDIT
classDef node fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef block fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef warn fill:#1a1a0d,stroke:#7a6a00,color:#fde68a

The WHQL level sits between WHQLPublisher/WHQLFilePublisher (more specific) and PcaCertificate (broader but different concept). More specific WHQL-based rules are checked first.


8. XML Representation#

A complete WHQL rule in App Control for Business XML consists of two parts:

  1. An EKU element defining the WHQL OID
  2. A Signer element referencing that EKU

Full XML Example#

<?xml version="1.0" encoding="utf-8"?>
<SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy">
<EKUs>
<EKU ID="ID_EKU_WHQL" Value="010A2B0601040182370A0305" />
</EKUs>
<Signers>
<!--
WHQL Signer: Trusts any file whose cert chain:
1. Contains the WHQL EKU (defined above)
2. Chains to Microsoft's WHQL root
This does NOT restrict to a specific vendor — any WHQL-certified driver matches.
-->
<Signer ID="ID_SIGNER_WHQL_KERNEL" Name="Windows Hardware Quality Lab (WHQL) - Kernel Mode">
<CertRoot Type="TBS" Value="3085A90B03EE71B6B33F5EA8A07DBBD40B5B7A89" />
<CertEKU ID="ID_EKU_WHQL" />
</Signer>
</Signers>
<SigningScenarios>
<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS" FriendlyName="Driver Signing Scenario">
<ProductSigners>
<AllowedSigner SignerID="ID_SIGNER_WHQL_KERNEL" />
</ProductSigners>
</SigningScenario>
</SigningScenarios>
<Rules>
<Rule>
<Option>Enabled:Unsigned System Integrity Policy</Option>
</Rule>
</Rules>
</SiPolicy>

Signing Scenario Values#

ValueScenarioApplies To
131Kernel ModeDrivers, kernel components
12User ModeExecutables, DLLs

WHQL rules are almost always placed in the kernel-mode signing scenario (131).


9. PowerShell Examples#

Generating a WHQL Policy#

Terminal window
# Generate a policy that allows all WHQL-certified kernel drivers
# New-CIPolicy with Level WHQL creates WHQL EKU-based Signer rules
New-CIPolicy `
-ScanPath "C:\Windows\System32\drivers\" `
-Level WHQL `
-Fallback Hash ` # For any drivers that are NOT WHQL-signed
-FilePath "C:\Policies\WHQL-Drivers-Policy.xml" `
-Drivers # Only scan drivers (kernel mode)
# Output: EKU element for WHQL OID + Signer elements for WHQL intermediate CAs
# Plus Hash rules for any non-WHQL-signed drivers found during scan

Checking If a Driver Is WHQL-Signed#

Terminal window
function Test-WHQLSigned {
param([string]$DriverPath)
# The WHQL EKU OID
$whqlOid = "1.3.6.1.4.1.311.10.3.5"
$sig = Get-AuthenticodeSignature -FilePath $DriverPath
if ($sig.Status -ne "Valid") {
Write-Warning "File is not validly signed: $DriverPath"
return $false
}
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($sig.SignerCertificate) | Out-Null
foreach ($element in $chain.ChainElements) {
$cert = $element.Certificate
foreach ($ext in $cert.Extensions) {
if ($ext -is [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]) {
foreach ($oid in $ext.EnhancedKeyUsages) {
if ($oid.Value -eq $whqlOid) {
Write-Host "WHQL-signed: $DriverPath" -ForegroundColor Green
Write-Host " WHQL EKU found in cert: $($cert.Subject)" -ForegroundColor Green
return $true
}
}
}
}
}
Write-Host "Not WHQL-signed: $DriverPath" -ForegroundColor Yellow
return $false
}
# Test a specific driver
Test-WHQLSigned -DriverPath "C:\Windows\System32\drivers\nvlddmkm.sys"

Scanning System32\drivers for WHQL Status#

Terminal window
# Audit all drivers on the system — identify which are WHQL-signed
$whqlOid = "1.3.6.1.4.1.311.10.3.5"
Get-ChildItem "C:\Windows\System32\drivers\*.sys" | ForEach-Object {
$driver = $_
$sig = Get-AuthenticodeSignature -FilePath $driver.FullName -ErrorAction SilentlyContinue
if ($sig -and $sig.Status -eq "Valid") {
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($sig.SignerCertificate) | Out-Null
$isWhql = $false
foreach ($el in $chain.ChainElements) {
foreach ($ext in $el.Certificate.Extensions) {
if ($ext -is [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]) {
if ($ext.EnhancedKeyUsages | Where-Object { $_.Value -eq $whqlOid }) {
$isWhql = $true
}
}
}
}
[PSCustomObject]@{
Driver = $driver.Name
Signer = $sig.SignerCertificate.Subject -replace "CN=",""
WHQLSigned = $isWhql
Status = $sig.Status
}
}
} | Sort-Object WHQLSigned, Driver | Format-Table -AutoSize
Terminal window
# Microsoft-recommended approach: allow WHQL drivers BUT apply the vulnerable driver block rules
# Step 1: Generate base WHQL policy
New-CIPolicy `
-Level WHQL `
-Fallback Hash `
-FilePath "C:\Policies\WHQL-Base.xml" `
-Drivers
# Step 2: Download Microsoft's recommended block rules (driver blocklist)
# Source: https://aka.ms/VulnerableDriverBlockList
# These block known vulnerable drivers that ARE WHQL-signed but have CVEs
Invoke-WebRequest `
-Uri "https://aka.ms/VulnerableDriverBlockList" `
-OutFile "C:\Policies\VulnerableDriverBlockList.xml"
# Step 3: Merge base policy with block rules
Merge-CIPolicy `
-PolicyPaths "C:\Policies\WHQL-Base.xml", "C:\Policies\VulnerableDriverBlockList.xml" `
-OutputFilePath "C:\Policies\WHQL-WithBlockList.xml"
# Step 4: Compile to binary
ConvertFrom-CIPolicy `
-XmlFilePath "C:\Policies\WHQL-WithBlockList.xml" `
-BinaryFilePath "C:\Policies\WHQL-WithBlockList.p7b"

10. WHQL vs. Option 02 (Required)#

This is one of the most common sources of confusion regarding WHQL in WDAC. These are two completely different concepts:

ConceptWhat It IsEffect
WHQL level (file rule level)A trust grant — “allow files that are WHQL-signed”Files with WHQL EKU are allowed to run
Option 02: RequiredA policy mandate — “all kernel drivers MUST be WHQL”Drivers without WHQL EKU are BLOCKED, regardless of other rules

Option 02 Explained#

Adding <Option>Required:WHQL</Option> to a WDAC policy’s <Rules> section activates a global kernel-mode policy that requires every kernel driver to be WHQL-certified. This is enforced by ci.dll before any signer rules are evaluated:

<Rules>
<Rule>
<Option>Required:WHQL</Option>
</Rule>
</Rules>

When you combine both:

graph TD
DRIVER_LOAD(["Kernel Driver Load Request"]):::node
OPT02{"Option 02\nRequired:WHQL\nin policy?"}:::node
WHQL_CHECK_OPT{"Does driver have\nWHQL EKU?"}:::node
OPT02_BLOCK(["BLOCKED — Option 02 mandate\ndriver lacks WHQL EKU\nNo signer rules evaluated"]):::block
RULE_EVAL["Evaluate WDAC Signer Rules\n(WHQL level, Publisher, Hash, etc.)"]:::node
WHQL_RULE{"WHQL signer rule\nexists AND EKU present?"}:::node
WHQL_RULE_ALLOW(["ALLOWED — WHQL rule matches"]):::allow
OTHER_RULE{"Other signer rules\nmatch?"}:::node
OTHER_ALLOW(["ALLOWED — Other rule matches"]):::allow
DEFAULT_BLOCK(["BLOCKED — Default deny"]):::block
DRIVER_LOAD --> OPT02
OPT02 -->|"Yes — Option 02 active"| WHQL_CHECK_OPT
OPT02 -->|"No — Option 02 absent"| RULE_EVAL
WHQL_CHECK_OPT -->|"No WHQL EKU"| OPT02_BLOCK
WHQL_CHECK_OPT -->|"Has WHQL EKU"| RULE_EVAL
RULE_EVAL --> WHQL_RULE
WHQL_RULE -->|"Yes"| WHQL_RULE_ALLOW
WHQL_RULE -->|"No"| OTHER_RULE
OTHER_RULE -->|"Yes"| OTHER_ALLOW
OTHER_RULE -->|"No"| DEFAULT_BLOCK
classDef node fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef block fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef warn fill:#1a1a0d,stroke:#7a6a00,color:#fde68a

Practical guidance:

  • Use WHQL level when you want to allow WHQL-certified drivers as a category
  • Use Option 02 when you want to mandate that all drivers must be WHQL (and block non-WHQL drivers even if they have other valid signatures)
  • For maximum security, use both: Option 02 mandates WHQL, and WHQL level rules allow them

11. Pros & Cons Table#

AttributeAssessment
Trust scopeAll WHQL-certified drivers — broad but bounded by Microsoft’s certification process
Maintenance burdenVery low — new WHQL drivers automatically match existing rules
Security validationHigh — Microsoft tested and signed each driver through HLK
False positive riskLow for kernel mode; WHQL is specific to hardware drivers
BYOVD vulnerabilityPresent — legitimate old WHQL drivers with CVEs still match
SpecificityLow — cannot distinguish NVIDIA driver from Intel driver at this level
Ease of useHigh — single EKU rule covers all certified drivers
User-mode applicabilityLimited — few user-mode binaries are WHQL-signed
CompatibilityExcellent — works on all WDAC-capable Windows versions
Kernel stabilityHigh — WHQL drivers have passed quality testing

12. Attack Resistance Analysis — BYOVD Context#

Bring Your Own Vulnerable Driver (BYOVD)#

The WHQL level’s most significant limitation is its vulnerability to BYOVD attacks. In a BYOVD attack, a threat actor loads a legitimately-signed, WHQL-certified driver that contains a known vulnerability (typically a kernel read/write primitive) and exploits it to escalate privileges or disable security software.

The key insight: WHQL certification tests whether a driver works correctly for its intended purpose on certified hardware. It does NOT:

  • Test for security vulnerabilities in the driver code
  • Expire or invalidate a signature when a CVE is discovered
  • Prevent old, vulnerable drivers from matching WDAC WHQL rules
graph TD
subgraph "BYOVD Attack Chain"
ATK1["Attacker runs with admin privileges\n(e.g., post-initial-access)"]:::warn
ATK2["Downloads vulnerable WHQL driver:\nkevp64.sys (Gigabyte driver, CVE-XXXX)\ndbutil_2_3.sys (Dell driver, CVE-2021-21551)\nnvflash.sys (NVIDIA tool, has kernel R/W)"]:::warn
ATK3["Loads driver via sc.exe or\nLoadDriver privilege"]:::warn
WDAC_CHECK{"WDAC WHQL check"}:::node
WHQL_PASS(["ALLOWED — Driver IS WHQL-signed\nWDAC WHQL rule matches\nDriver loads successfully"]):::block
ATK4["Exploits kernel vulnerability\nin loaded driver\n(arbitrary kernel R/W, process token\nmanipulation, PPL bypass, etc.)"]:::block
ATK5["Disables EDR/AV,\nescalates to SYSTEM,\nor installs kernel rootkit"]:::block
end
subgraph "Mitigation: Microsoft Vulnerable Driver Blocklist"
BLOCK_LIST["Microsoft-maintained deny list:\n/windows/security/application-security/\napplication-control/windows-defender-\napplication-control/design/\nrecommended-driver-block-rules"]:::allow
BLOCK_CHECK{"Driver hash/signer\nin block list?"}:::node
BLOCKED(["BLOCKED — Even though WHQL-signed\nDeny rule takes precedence\nover WHQL allow rule"]):::allow
end
ATK1 --> ATK2
ATK2 --> ATK3
ATK3 --> WDAC_CHECK
WDAC_CHECK -->|"WHQL rule exists, EKU found"| WHQL_PASS
WHQL_PASS --> ATK4
ATK4 --> ATK5
ATK3 -.->|"With block list enabled"| BLOCK_CHECK
BLOCK_CHECK -->|"Yes — in block list"| BLOCKED
classDef node fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef block fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef warn fill:#1a1a0d,stroke:#7a6a00,color:#fde68a

Mitigating BYOVD When Using WHQL Level#

The WHQL level should always be combined with Microsoft’s recommended driver block rules (the vulnerable driver blocklist). This list contains hashes and signer rules for known-vulnerable WHQL-certified drivers. Since deny rules take precedence over allow rules in WDAC, drivers on the block list are blocked even if they would otherwise match the WHQL allow rule.

Key point: WHQL level alone is insufficient for BYOVD protection. Always combine with:

  1. Microsoft’s vulnerable driver block rules (updated regularly)
  2. WHQLFilePublisher level rules for specific known-good drivers (more restrictive)
  3. Required:WHQL option (Option 02) to block unsigned kernel drivers

13. When to Use vs. When to Avoid — Decision Flowchart#

flowchart TD
Q1["Goal: Control which kernel drivers\ncan load on my systems"]:::node
Q2{"Do you need to control\nwhich VENDORS' drivers run?"}:::node
Q3{"Are ALL drivers from a\nsingle known set of vendors?"}:::node
USE_WHQL(["Consider WHQL level\n+ Microsoft block rules\n+ Option 02 (Required:WHQL)\nBest for: broad enterprise\ndriver allowlisting where\nyou trust all WHQL-certified vendors"]):::allow
USE_WHQL_PUB(["Use WHQLPublisher level\nTrust WHQL drivers from\nspecific vendors only\nBest for: OEM-specific\ndriver allowlisting"]):::allow
USE_WHQL_FP(["Use WHQLFilePublisher level\nTrust specific WHQL drivers\nby filename + version + vendor\nBest for: production policy\nwith known driver inventory"]):::allow
Q4{"Security requirement\nlevel?"}:::node
HIGH_SEC(["High security environment\n→ WHQLFilePublisher preferred\n→ Enumerate specific drivers\n→ Add Microsoft block rules\n→ Enable Option 02"]):::warn
STD_SEC(["Standard enterprise\n→ WHQL level is acceptable\n→ Must add Microsoft block rules\n→ Recommended: enable Option 02\n→ Monitor for CVE advisories"]):::allow
Q1 --> Q2
Q2 -->|"Any WHQL vendor is fine"| Q4
Q2 -->|"Specific vendors only"| Q3
Q3 -->|"Yes, one or few vendors"| USE_WHQL_PUB
Q3 -->|"Specific files known"| USE_WHQL_FP
Q4 -->|"High security / strict"| HIGH_SEC
Q4 -->|"Standard enterprise"| STD_SEC
STD_SEC --> USE_WHQL
HIGH_SEC --> USE_WHQL_FP
classDef node fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef block fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef warn fill:#1a1a0d,stroke:#7a6a00,color:#fde68a

14. Real-World Scenario: End-to-End Sequence#

Scenario: A manufacturing company deploys WDAC to their workstations. They have various hardware with drivers from Intel, NVIDIA, Realtek, and other vendors. They want to allow all properly-certified drivers without enumerating each vendor.

sequenceDiagram
participant Admin as IT Admin
participant PS as PowerShell (ConfigCI)
participant MSBlock as Microsoft Block Rules Feed
participant MDM as Intune/MDM
participant WS as Workstation (ci.dll)
participant Driver as Vendor Driver (nvlddmkm.sys)
Note over Admin,Driver: Phase 1 — Policy Creation
Admin->>PS: New-CIPolicy -Level WHQL -Fallback Hash -Drivers -FilePath base.xml
PS-->>Admin: base.xml — contains WHQL EKU rule + Hash rules for any non-WHQL drivers
Admin->>MSBlock: Download recommended driver block rules (aka.ms/VulnerableDriverBlockList)
MSBlock-->>Admin: blocklist.xml — deny rules for known-vulnerable WHQL drivers
Admin->>PS: Merge-CIPolicy -PolicyPaths base.xml, blocklist.xml -OutputFilePath merged.xml
Admin->>PS: Add Option 02 (Required:WHQL) to merged.xml
Admin->>PS: ConvertFrom-CIPolicy -XmlFilePath merged.xml -BinaryFilePath policy.p7b
Note over Admin,Driver: Phase 2 — Deployment
Admin->>MDM: Upload policy.p7b, deploy via OMA-URI to workstations
MDM-->>WS: Policy deployed and activated
Note over Admin,Driver: Phase 3 — Normal Operation (WHQL driver allowed)
Driver->>WS: NVIDIA driver update: nvlddmkm.sys v560.94 loads
WS->>WS: ci.dll — kernel mode evaluation
WS->>WS: Check Option 02: nvlddmkm.sys has WHQL EKU? Yes → proceed
WS->>WS: Evaluate WHQL signer rule: EKU OID 1.3.6.1.4.1.311.10.3.5 found in chain? Yes
WS->>WS: Check Microsoft block list: v560.94 hash in deny list? No
WS-->>Driver: ALLOWED — WHQL-certified, not on block list
Note over Admin,Driver: Phase 4 — BYOVD Attempt (blocked by deny list)
Driver->>WS: Attacker tries to load kevp64.sys (Gigabyte, known vulnerable, WHQL-signed)
WS->>WS: ci.dll — kernel mode evaluation
WS->>WS: Check Option 02: kevp64.sys has WHQL EKU? Yes → proceed to rules
WS->>WS: Check Microsoft block list: kevp64.sys hash in deny list? YES
WS-->>Driver: BLOCKED — Deny rule (block list) takes precedence over WHQL allow rule
WS->>WS: Event ID 3077 logged (CI block event)

15. OS Version & Compatibility#

OS VersionWHQL Level SupportNotes
Windows 10 1507+Full supportWDAC kernel-mode signing scenarios
Windows 10 1709+Full support + Audit ModeSeparate audit/enforce policy support
Windows 11 21H2+Full supportEnhanced kernel security, HVCI
Windows Server 2016+Full supportServer supports WDAC kernel driver control
Windows Server 2019+Full supportRecommended for server deployments
Windows Server 2022+Full supportStrong WDAC integration with Secured-Core
ARM64Full supportWHQL covers ARM64 drivers as well

Note on HVCI (Hypervisor-Protected Code Integrity): When HVCI (Memory Integrity) is enabled, kernel driver loading is validated by the hypervisor using WDAC policies. WHQL rules work identically in HVCI mode. The additional protection HVCI provides is that even if ci.dll were compromised, the hypervisor enforces the policy independently.


16. Common Mistakes & Gotchas#

Mistake 1: Believing WHQL Means the Driver Is Secure#

Wrong assumption: “WHQL drivers are Microsoft-approved, so they’re safe to run.”

Reality: WHQL certification tests hardware compatibility and quality, not security. A driver can be WHQL-certified and still contain exploitable vulnerabilities (as demonstrated by dozens of CVEs in WHQL-signed drivers). Always combine WHQL rules with Microsoft’s vulnerable driver block list.

Mistake 2: Forgetting the Fallback#

Wrong approach: Using WHQL level without a fallback for legacy or internal drivers that are not WHQL-certified.

Reality: Many legitimate enterprise drivers (especially legacy hardware or internal development drivers) are not WHQL-signed. Without a fallback (-Fallback Hash or -Fallback Publisher), these drivers will be blocked.

Fix: Always specify -Fallback Hash or another appropriate fallback level when generating WHQL policies.

Mistake 3: Confusing WHQL Level with Option 02#

As described in Section 10, these are different. Confusing them leads to policies that either:

  • Allow non-WHQL drivers when you intended to block them (forgot Option 02)
  • Block valid driver loads that only have PcaCertificate rules (added Option 02 without WHQL allow rules)

Mistake 4: Not Updating the Block List#

Wrong assumption: “Once I add the Microsoft block list to my policy, I’m protected forever.”

Reality: New vulnerable WHQL-signed drivers are discovered regularly. Microsoft updates the block list. Your deployed policy does not auto-update. Schedule regular policy reviews to incorporate updated block rules.

Mistake 5: Applying WHQL Rules to User-Mode Scenario#

WHQL rules are meaningful only in the kernel-mode signing scenario (value 131). Adding WHQL EKU rules to user-mode scenario (value 12) rules has no meaningful effect because user-mode binaries are almost never WHQL-signed. If you see WHQL rules in a user-mode policy section, they are likely the result of an overly broad scan and can be removed.

Mistake 6: The EKU Hex Value Encoding#

The WHQL EKU value in WDAC XML (010A2B0601040182370A0305) is not the raw OID in hex. It is a specific encoding format used by WDAC. Using the wrong encoding (e.g., raw ASN.1 OID bytes without the WDAC-specific prefix) will cause the EKU rule to never match, silently failing to allow WHQL drivers.

Always use the canonical value 010A2B0601040182370A0305 for the WHQL EKU in WDAC XML.


17. Summary Table#

PropertyValue
Level NameWHQL
Trust MechanismEKU OID 1.3.6.1.4.1.311.10.3.5 in cert chain
EKU Hex (WDAC XML)010A2B0601040182370A0305
Primary Use CaseKernel-mode driver allowlisting
Trust ScopeAll Microsoft-certified WHQL drivers
Vendor SpecificityNone — any WHQL driver from any vendor matches
BYOVD RiskPresent — old vulnerable WHQL drivers still match
BYOVD MitigationMicrosoft vulnerable driver block rules
Related OptionOption 02 Required:WHQL (mandate, not grant)
More Specific AlternativesWHQLPublisher (adds vendor CN), WHQLFilePublisher (adds filename+version)
Signing ScenarioKernel mode (131) — rarely user mode (12)
PowerShell Level NameWHQL
Kernel Componentci.dll (Code Integrity)
OS SupportWindows 10 1507+ / Server 2016+
HVCI CompatibleYes — evaluated by hypervisor in HVCI mode
Block List URLhttps://aka.ms/VulnerableDriverBlockList
WDAC File Rule Level: WHQL
https://mranv.pages.dev/posts/app-control-file-rule-level-whql/
Author
Anubhav Gain
Published at
2026-05-02
License
CC BY-NC-SA 4.0