3615 words
18 minutes
WDAC File Rule Level: RootCertificate

WDAC File Rule Level: RootCertificate#

CRITICAL: The RootCertificate level is NOT SUPPORTED in App Control for Business (WDAC). This document explains why, what happens if you try to use it, and what you should use instead.


Table of Contents#

  1. Overview
  2. Why RootCertificate Is Not Supported
  3. The Trust Surface Explosion Problem
  4. Certificate Chain Anatomy
  5. Where in the Evaluation Stack
  6. What Happens If You Try It
  7. XML Representation (Attempted vs. Correct)
  8. PowerShell Examples
  9. The Correct Alternative: PcaCertificate
  10. Pros & Cons Table
  11. Attack Resistance Analysis
  12. When to Use vs. When to Avoid — Decision Flowchart
  13. Real-World Scenario: End-to-End Sequence
  14. OS Version & Compatibility
  15. Common Mistakes & Gotchas
  16. Historical Context
  17. Summary Table

1. Overview#

App Control for Business (the successor to Windows Defender Application Control, still internally called WDAC) uses a tiered system of file rule levels to determine how broadly or narrowly a policy trusts signed binaries. These levels range from highly specific (Hash) to broadly generalized certificate-based trust.

RootCertificate sits conceptually at the very top of the certificate trust chain — it represents the self-signed root CA that anchors an entire PKI hierarchy. In most PKI models, trusting the root means trusting every single certificate ever issued under it, including intermediate CAs and every leaf certificate they sign.

This is precisely why RootCertificate is explicitly excluded from WDAC’s supported rule levels.

The supported rule levels in App Control for Business, from broadest to most specific, are:

LevelDescription
PCACertificateIntermediate (PCA) CA cert — the level just below root
PublisherLeaf cert CN + PCA combined
FilePublisherPublisher + file name + minimum version
SignedVersionPublisher + minimum version (no filename)
PcaCertificateSame as PCACertificate (alias)
RootCertificateNOT SUPPORTED
WHQLWindows Hardware Quality Lab EKU
WHQLPublisherWHQL EKU + leaf CN
WHQLFilePublisherWHQL EKU + leaf CN + filename + version
FileNameFile’s internal OriginalFileName attribute
FilePathSpecific file path on disk
HashCryptographic hash of file contents

Notice that RootCertificate appears in the conceptual hierarchy but is marked NOT SUPPORTED. If you attempt to generate rules at this level, WDAC tooling will either refuse or fall back silently to a different level.


2. Why RootCertificate Is Not Supported#

The Core Problem: Catastrophically Broad Trust#

A root CA certificate is the trust anchor for an entire certificate hierarchy. A single root CA may have signed dozens or hundreds of intermediate CAs. Each intermediate CA may have issued thousands of leaf certificates. Each leaf certificate may be used to sign hundreds of software binaries.

If WDAC allowed RootCertificate as a rule level, a single XML entry saying “trust Microsoft Root Certificate Authority 2010” would implicitly authorize every binary signed by:

  • Every Microsoft product team
  • Every third-party ISV that received a code-signing certificate from Microsoft’s PKI
  • Every driver vendor certified by WHQL
  • Every OEM that received an Authenticode certificate under the Microsoft hierarchy
  • Historical artifacts and legacy software signed years ago

This is equivalent to saying “allow anything that has ever been vouched for by Microsoft, in any context, for any purpose” — which completely defeats the purpose of application whitelisting.

The Specific Example: Microsoft Root CA#

Consider Microsoft’s own certificate hierarchy:

Microsoft Root Certificate Authority 2010
└── Microsoft Code Signing PCA 2011
├── Microsoft Corporation (leaf — signs Windows binaries)
├── Microsoft Windows (leaf — signs OS components)
└── [hundreds of other leaf certs]
└── Microsoft Time-Stamp PCA 2011
└── Microsoft Azure TLS Issuing CA 01-08
└── [dozens of other intermediate CAs]

Trusting the root would allow ALL of these. There is no mechanism to say “trust the root, but only for binaries from this one product team.” The granularity simply does not exist at the root level.

The Contoso Example#

Suppose your organization uses an internal CA called “Contoso Root CA” to sign internal software. You want WDAC to allow all Contoso-signed software. A naive approach might be:

“I’ll create a RootCertificate rule for Contoso Root CA.”

The problem: “Contoso Root CA” likely signs:

  • Internal application A
  • Internal application B
  • VPN client certificates
  • Email S/MIME certificates
  • Web server TLS certificates
  • Contractor laptop certificates

Trusting the root allows anyone with any Contoso-issued certificate — including a contractor who received a personal auth certificate — to run arbitrary signed binaries. The correct approach is to trust the specific intermediate CA used only for code signing, not the root.


3. The Trust Surface Explosion Problem#

graph TD
ROOT["Microsoft Root CA 2010\n(Self-Signed)"]:::root
PCA1["Microsoft Code Signing PCA 2011"]:::pca
PCA2["Microsoft Time-Stamp PCA 2011"]:::pca
PCA3["Microsoft Azure TLS Issuing CA"]:::pca
PCA4["Microsoft Windows Hardware Compatibility PCA"]:::pca
LEAF1["Microsoft Corporation\n(Authenticode)"]:::leaf
LEAF2["Microsoft Windows\n(OS Signing)"]:::leaf
LEAF3["NVIDIA Corporation\n(WHQL Driver Signing)"]:::leaf
LEAF4["Intel Corporation\n(WHQL Driver Signing)"]:::leaf
LEAF5["Adobe Systems\n(3rd party ISV)"]:::leaf
FILE1["calc.exe"]:::file
FILE2["notepad.exe"]:::file
FILE3["nvlddmkm.sys"]:::file
FILE4["e1d68x64.sys"]:::file
FILE5["AcroRd32.exe"]:::file
TRUST_SURFACE["EVERYTHING ABOVE IS ALLOWED\nif RootCertificate rule exists\nfor Microsoft Root CA 2010\n\nThis is thousands of binaries\nfrom hundreds of publishers"]:::danger
ROOT --> PCA1
ROOT --> PCA2
ROOT --> PCA3
ROOT --> PCA4
PCA1 --> LEAF1
PCA1 --> LEAF2
PCA1 --> LEAF3
PCA1 --> LEAF4
PCA1 --> LEAF5
LEAF1 --> FILE1
LEAF2 --> FILE2
LEAF3 --> FILE3
LEAF4 --> FILE4
LEAF5 --> FILE5
FILE1 & FILE2 & FILE3 & FILE4 & FILE5 --> TRUST_SURFACE
classDef root fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef pca fill:#1a0d2e,stroke:#6b21a8,color:#d8b4fe
classDef leaf fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef file fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef danger fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5

This diagram illustrates why root-level trust is unworkable: a single rule at the root exposes the entire downstream subtree of certificates and files. WDAC’s designers explicitly rejected this model.


4. Certificate Chain Anatomy#

Understanding why root-level trust is dangerous requires understanding the full certificate chain and what each level represents in WDAC.

graph TB
subgraph "Certificate Chain (Top to Bottom)"
R["Root CA Certificate\n(Self-Signed, air-gapped HSM)\nThumbprint: A4341..."]:::root
I1["Intermediate CA (PCA)\nIssued by Root CA\nPurpose: Code Signing\nThumbprint: B2291..."]:::pca
I2["(Optional) Sub-Intermediate\nIssued by PCA\nThumbprint: C3371..."]:::pca
L["Leaf Certificate\nIssued to: Vendor Name\nCN=NVIDIA Corporation\nThumbprint: D4481..."]:::leaf
F["Binary File\nnvlddmkm.sys\nSigned by Leaf Cert\nContains embedded signature"]:::file
end
subgraph "WDAC Rule Levels (What Each Maps To)"
RL["RootCertificate\n[NOT SUPPORTED]\nWould match Thumbprint A4341..."]:::danger
PL["PcaCertificate\n[SUPPORTED — Broadest Allowed]\nMatches Thumbprint B2291..."]:::warn
PUB["Publisher\n[SUPPORTED]\nMatches B2291... + CN=NVIDIA Corporation"]:::ok
FP["FilePublisher\n[SUPPORTED — Most Specific]\nMatches B2291... + CN + nvlddmkm.sys + v1.0+"]:::ok
end
R --> I1
I1 --> I2
I2 --> L
L --> F
R -.->|"Would match"| RL
I1 -.->|"Matches"| PL
L -.->|"Contributes to"| PUB
F -.->|"Contributes to"| FP
classDef root fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef pca fill:#1a0d2e,stroke:#6b21a8,color:#d8b4fe
classDef leaf fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef file fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef danger fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef warn fill:#1a1a0d,stroke:#7a6a00,color:#fde68a
classDef ok fill:#0d1f12,stroke:#1a5c2a,color:#86efac

Key insight: WDAC deliberately skips the root level and starts at the PCA (intermediate) level as the broadest permitted trust anchor. This forces policy authors to make a conscious decision about which intermediate CA they trust, rather than blindly inheriting everything from a root.


5. Where in the Evaluation Stack#

When WDAC evaluates a file, ci.dll (the Code Integrity kernel component) walks through the policy rules in a specific order. Even if RootCertificate were supported, understanding where it would fall helps clarify why it is rejected.

flowchart TD
START(["File Execution Requested"]):::node
HASH_CHECK{"Hash rule\nexists for this file?"}:::node
HASH_ALLOW(["ALLOW — Hash match"]):::allow
LEAF_CHECK{"Leaf cert rule\nexists? (Publisher/\nFilePublisher)"}:::node
LEAF_ALLOW(["ALLOW — Publisher match"]):::allow
PCA_CHECK{"PcaCertificate rule\nexists for signer\nchain?"}:::node
PCA_ALLOW(["ALLOW — PcaCertificate match"]):::allow
ROOT_CHECK{"RootCertificate rule\nexists?"}:::warn
ROOT_SKIP(["SKIPPED — Not evaluated\nci.dll ignores this level\nRule has no effect"]):::block
DEFAULT{"Default action\nin policy?"}:::node
BLOCK(["BLOCK — Execution denied"]):::block
ALLOW_ALL(["ALLOW — Default allow\n(Audit-only mode)"]):::allow
START --> HASH_CHECK
HASH_CHECK -->|"Yes"| HASH_ALLOW
HASH_CHECK -->|"No"| LEAF_CHECK
LEAF_CHECK -->|"Yes"| LEAF_ALLOW
LEAF_CHECK -->|"No"| PCA_CHECK
PCA_CHECK -->|"Yes"| PCA_ALLOW
PCA_CHECK -->|"No"| ROOT_CHECK
ROOT_CHECK -->|"RootCert rule found"| ROOT_SKIP
ROOT_SKIP --> DEFAULT
ROOT_CHECK -->|"No rule"| DEFAULT
DEFAULT -->|"DefaultDeny"| BLOCK
DEFAULT -->|"DefaultAllow/Audit"| ALLOW_ALL
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 evaluation engine simply does not have a code path that validates RootCertificate rules. If such a rule were somehow injected into a compiled policy binary, the kernel-mode Code Integrity (CI) component would either fail to parse it or silently skip it during rule evaluation. The file would then fall through to the default action.


6. What Happens If You Try It#

Attempting with PowerShell#

If you run:

Terminal window
New-CIPolicy -ScanPath "C:\Windows\System32" -Level RootCertificate -FilePath ".\test-policy.xml"

The WDAC tooling (ConfigCI module) will silently fall back to PcaCertificate and generate rules at that level instead. The output XML will contain <Signer> elements referencing the intermediate CA, not the root. There is no error message. The tooling simply treats RootCertificate as an invalid level and promotes the rules to the nearest supported level.

Attempting with Direct XML Authoring#

If you manually craft XML with a <Signer> element that references a root certificate’s thumbprint and add it to a WDAC policy, the following occurs:

  1. The policy compiles (no compile-time error)
  2. When deployed, ci.dll evaluates the rule
  3. The rule does not match files, because the matching algorithm for signer rules compares against intermediate CA certificates, not root certificates
  4. The binary fails to match the malformed rule
  5. The binary falls through to the default action (typically deny in production policies)
  6. The file is blocked — the opposite of what was intended

This is a dangerous silent failure mode. Policy authors who craft such rules will believe they have allowed a set of files, but those files will actually be blocked. This can cause system instability or application failures.


7. XML Representation (Attempted vs. Correct)#

Incorrect Approach (Root Level — Do NOT Use)#

<Signer ID="ID_SIGNER_ROOT_EXAMPLE" Name="Microsoft Root Certificate Authority 2010">
<CertRoot Type="TBS" Value="D8C5388AB7301B1BB6A09FE8097E4DE9C1A3C1E7..." />
</Signer>

Correct Approach (PCA Level — Use This)#

<Signer ID="ID_SIGNER_MSFT_PCA" Name="Microsoft Code Signing PCA 2011">
<CertRoot Type="TBS" Value="F252E794FE438E35ACE6E53762C0A234A2C52135" />
</Signer>
<ProductSigners>
<AllowedSigner SignerID="ID_SIGNER_MSFT_PCA" />
</ProductSigners>

The TBS (To-Be-Signed) Hash#

WDAC uses the TBS (To-Be-Signed) hash of the certificate, not the full certificate thumbprint. The TBS hash covers the subject, public key, validity period, and extensions — the actual content that was signed by the issuing CA — but excludes the issuing CA’s signature itself. This makes it stable across certificate renewals that preserve the same key and subject.

To compute the TBS hash for a certificate:

Terminal window
# Get the TBS hash of a certificate from a signed file
$cert = (Get-AuthenticodeSignature "C:\Windows\System32\ntoskrnl.exe").SignerCertificate
# Walk the chain to find the intermediate CA
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($cert) | Out-Null
$intermediateCert = $chain.ChainElements[1].Certificate # Index 1 = intermediate, 0 = leaf, 2 = root
# Display the TBS hash (used in WDAC XML)
$intermediateCert.GetRawCertData() | ForEach-Object { [System.BitConverter]::ToString($_).Replace("-","") }

8. PowerShell Examples#

Scanning and Generating Rules (Correct Level)#

Terminal window
# Generate a policy using PcaCertificate level (the correct alternative to RootCertificate)
# This creates Signer rules for intermediate CAs — not root CAs
New-CIPolicy `
-ScanPath "C:\Program Files\MyApp\" `
-Level PcaCertificate `
-Fallback Hash `
-FilePath "C:\Policies\MyApp-PCA-Policy.xml" `
-UserPEs
# Output: Signer elements referencing intermediate CA certs, Hash rules for unsigned files
Terminal window
# What happens if you accidentally specify RootCertificate:
New-CIPolicy `
-ScanPath "C:\Program Files\MyApp\" `
-Level RootCertificate ` # <-- Unsupported
-Fallback Hash `
-FilePath "C:\Policies\test.xml"
# Result: WDAC tooling silently promotes to PcaCertificate level
# The output XML will contain intermediate CA signers, not root CA signers
# No error is raised — this is a silent behavior change

Inspecting the Certificate Chain of a Signed File#

Terminal window
function Get-WDACSignerInfo {
param([string]$FilePath)
$sig = Get-AuthenticodeSignature -FilePath $FilePath
if ($sig.Status -ne "Valid") {
Write-Warning "File is not validly signed: $FilePath"
return
}
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.Build($sig.SignerCertificate) | Out-Null
$elements = $chain.ChainElements
Write-Host "Chain for: $FilePath" -ForegroundColor Cyan
Write-Host ""
for ($i = $elements.Count - 1; $i -ge 0; $i--) {
$cert = $elements[$i].Certificate
$level = switch ($i) {
{ $_ -eq ($elements.Count - 1) } { "ROOT (Not used in WDAC rules)" }
0 { "LEAF (Used in Publisher/FilePublisher)" }
default { "INTERMEDIATE/PCA (Used in PcaCertificate rules)" }
}
Write-Host "[$level]" -ForegroundColor $(if ($i -eq ($elements.Count - 1)) { "Red" } elseif ($i -eq 0) { "Green" } else { "Yellow" })
Write-Host " Subject: $($cert.Subject)"
Write-Host " Thumbprint: $($cert.Thumbprint)"
Write-Host ""
}
}
# Example usage:
Get-WDACSignerInfo -FilePath "C:\Windows\System32\ntoskrnl.exe"

Verifying That a Policy Has No Root-Level Rules#

Terminal window
function Test-WDACPolicyForRootRules {
param([string]$PolicyXmlPath)
[xml]$policy = Get-Content -Path $PolicyXmlPath
$ns = @{ si = "urn:schemas-microsoft-com:sipolicy" }
$signers = $policy.SelectNodes("//si:Signer",
([System.Xml.XmlNamespaceManager]::new([xml]$policy | Select-Object -ExpandProperty NameTable)))
# Root CA certs are typically self-signed (Subject == Issuer)
# In practice, check if any signer thumbprint matches known root CA thumbprints
# This is a heuristic — proper validation requires checking the actual cert
Write-Host "Policy: $PolicyXmlPath"
Write-Host "Signer count: $($signers.Count)"
Write-Host ""
Write-Host "Note: WDAC does not support RootCertificate level rules." -ForegroundColor Yellow
Write-Host "All signers in this policy should reference intermediate CA (PCA) certificates." -ForegroundColor Yellow
Write-Host "If any signer references a self-signed root CA, it will be silently ignored." -ForegroundColor Red
}

9. The Correct Alternative: PcaCertificate#

The PcaCertificate level trusts binaries whose certificate chain contains a specific intermediate CA (PCA) certificate. This is:

  • Broad enough to cover all software signed by a CA’s leaf certs
  • Specific enough to exclude unrelated certificate hierarchies
  • The exact security boundary that WDAC’s designers intended
graph TD
subgraph "PcaCertificate — Correct Scoping"
ROOT2["Microsoft Root CA 2010\n(NOT in WDAC rule)"]:::root
PCA_A["Microsoft Code Signing PCA 2011\n← WDAC rule anchors HERE\nTrusted scope: all files signed\nunder this specific PCA"]:::pca_trusted
PCA_B["Microsoft Time-Stamp PCA 2011\n← NOT in WDAC rule\nTimestamping only — not code"]:::pca_untrusted
PCA_C["Microsoft Azure TLS CA\n← NOT in WDAC rule\nTLS/Web — not code signing"]:::pca_untrusted
LEAF_OK1["Microsoft Corporation\n(Allowed via PCA_A rule)"]:::allow
LEAF_OK2["Windows Components\n(Allowed via PCA_A rule)"]:::allow
LEAF_NO1["Azure CDN Service\n(Blocked — not under PCA_A)"]:::block
LEAF_NO2["Timestamp Service\n(Blocked — not under PCA_A)"]:::block
end
ROOT2 --> PCA_A
ROOT2 --> PCA_B
ROOT2 --> PCA_C
PCA_A --> LEAF_OK1
PCA_A --> LEAF_OK2
PCA_B --> LEAF_NO1
PCA_C --> LEAF_NO2
classDef root fill:#162032,stroke:#1e3a5f,color:#e2e8f0
classDef pca_trusted fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef pca_untrusted fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5
classDef allow fill:#0d1f12,stroke:#1a5c2a,color:#86efac
classDef block fill:#1f0d0d,stroke:#7f1d1d,color:#fca5a5

When to Choose Which PCA#

ScenarioCorrect PCA to Trust
Allow all Windows OS binariesMicrosoft Windows PCA 2011
Allow all Microsoft signed applicationsMicrosoft Code Signing PCA 2011
Allow WHQL-certified driversUse WHQL level instead (EKU-based)
Allow internal Contoso appsContoso Code Signing Intermediate CA
Allow specific vendor softwareVendor’s code-signing intermediate CA

The key principle: identify the specific intermediate CA used for code signing — not the root — and trust that. This limits scope to software that specifically went through that CA’s issuance process.


10. Pros & Cons Table#

Note: Since RootCertificate is not supported, this table compares the conceptual RootCertificate level against the recommended PcaCertificate level.

AttributeRootCertificate (Conceptual)PcaCertificate (Recommended)
Supported in WDACNo — not supportedYes — fully supported
Trust scopeEntire PKI tree from root downOnly subtree under specific intermediate CA
Security riskCatastrophically broadManageable — bounded by CA purpose
Maintenance burdenLow (set once, forget)Low (intermediate CAs rarely change)
False positive riskExtreme — allows unrelated certsLow — focused on code-signing CA
Attack surfaceAny cert from the root hierarchyOnly certs from the specific intermediate
WDAC tooling supportNone — silently falls back to PCAFull support in ConfigCI PowerShell
XML authoringBroken — ci.dll ignores itCorrect — matches expected Signer format
Practical equivalentn/aThe correct choice for broad CA trust

11. Attack Resistance Analysis#

graph TD
subgraph "Attack Scenario A: Compromised Intermediate CA"
ATK_A["Attacker obtains leaf cert\nfrom a DIFFERENT intermediate CA\nunder the same root"]:::block
CHECK_A{"Is the leaf cert under\nthe trusted PcaCertificate?"}:::node
BLOCK_A(["BLOCKED — Different PCA\nPcaCertificate rule does not match"]):::block
ATK_A --> CHECK_A
CHECK_A -->|"No (different PCA)"| BLOCK_A
end
subgraph "Attack Scenario B: Stolen Leaf Certificate"
ATK_B["Attacker steals a valid leaf cert\nfrom under the trusted PCA"]:::warn
CHECK_B{"Leaf cert under\ntrusted PCA?"}:::node
PASS_B(["ALLOWED — PcaCertificate matches\nThis is expected behavior\nMitigate with Publisher/FilePublisher levels"]):::warn
ATK_B --> CHECK_B
CHECK_B -->|"Yes"| PASS_B
end
subgraph "If RootCertificate Were Supported (Hypothetical)"
ATK_C["Attacker gets ANY cert from\nany intermediate under the root"]:::block
CHECK_C{"ANY cert under root?"}:::node
ALLOW_C(["ALLOWED — Root rule matches\nNo way to limit to specific CA branch"]):::block
ATK_C --> CHECK_C
CHECK_C -->|"Yes (any)"| ALLOW_C
end
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

Key security insight: Even PcaCertificate is vulnerable to stolen leaf certs from under the trusted intermediate. This is why, for high-security environments, Publisher or FilePublisher levels (which also check the leaf cert’s CN) are preferred. RootCertificate would be strictly worse than all alternatives.


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

flowchart TD
Q1["Goal: Trust all software\nsigned by a specific CA"]:::node
Q2{"Is this a root CA\nor intermediate CA?"}:::node
ROOT_ANS["It's a ROOT CA"]:::warn
INT_ANS["It's an INTERMEDIATE CA"]:::node
Q3{"How broad do you\nneed the trust to be?"}:::node
USE_PCA(["Use PcaCertificate level\n— Trust all files from any\nleaf cert under this intermediate CA\n— Correct and supported"]):::allow
USE_PUB(["Use Publisher level\n— Trust files from specific\nleaf CN under this PCA\n— More restrictive"]):::allow
USE_FP(["Use FilePublisher level\n— Trust specific files from\nspecific leaf CN + version\n— Most restrictive"]):::allow
ROOT_ADV["Find the code-signing\nINTERMEDIATE CA\n(not the root itself)"]:::warn
ROOT_AVOID(["Do NOT use RootCertificate\n— Not supported in WDAC\n— Would be too broad even if it were"]):::block
Q1 --> Q2
Q2 -->|"Root CA"| ROOT_ANS
Q2 -->|"Intermediate CA"| INT_ANS
ROOT_ANS --> ROOT_AVOID
ROOT_ANS --> ROOT_ADV
ROOT_ADV --> USE_PCA
INT_ANS --> Q3
Q3 -->|"All files from CA"| USE_PCA
Q3 -->|"Files from specific publisher"| USE_PUB
Q3 -->|"Specific files + version"| USE_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

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

Scenario: An IT admin at Contoso wants to create a WDAC policy that allows all software signed by the company’s internal code-signing infrastructure. They initially try RootCertificate and discover why it fails, then implement the correct approach.

sequenceDiagram
participant Admin as IT Admin
participant PS as PowerShell (ConfigCI)
participant XML as Policy XML
participant CI as ci.dll (Kernel)
participant File as Internal App (signed)
Note over Admin,File: Phase 1 — Incorrect Attempt with RootCertificate
Admin->>PS: New-CIPolicy -Level RootCertificate -ScanPath "C:\InternalApps"
PS-->>Admin: [No error, but silently falls back to PcaCertificate level]
PS->>XML: Creates Signer referencing intermediate CA (not root)
Admin->>Admin: Examines XML, confused — expected root CA, sees intermediate
Note over Admin,File: Phase 2 — Understanding the Correct Model
Admin->>PS: Get-AuthenticodeSignature "C:\InternalApps\app.exe" | Select SignerCertificate
PS-->>Admin: Returns leaf certificate info
Admin->>PS: Walk chain to find intermediate CA
PS-->>Admin: "Contoso Code Signing CA 2022" (intermediate, not root)
Admin->>Admin: Understands: WDAC uses PcaCertificate (intermediate) level
Note over Admin,File: Phase 3 — Correct Implementation
Admin->>PS: New-CIPolicy -Level PcaCertificate -ScanPath "C:\InternalApps" -FilePath policy.xml
PS->>XML: Creates correct Signer for "Contoso Code Signing CA 2022"
Admin->>CI: Deploys compiled policy via MDM/Group Policy
File->>CI: Requests execution (app.exe)
CI->>CI: Validates cert chain of app.exe
CI->>CI: Finds "Contoso Code Signing CA 2022" in chain
CI->>CI: Matches against PcaCertificate Signer in policy
CI-->>File: ALLOWED — chain matches trusted intermediate CA
Note over Admin,File: Phase 4 — Confirming Root-Level Attempts Are Ineffective
Admin->>XML: Manually adds Signer for "Contoso Root CA" (root cert)
Admin->>CI: Redeploys policy with root-level Signer
File->>CI: Requests execution (new-app.exe)
CI->>CI: Evaluates rules — root Signer is skipped/not matched
CI-->>File: Falls through to default action (BLOCKED in production)
Admin->>Admin: Confirms: RootCertificate rules have no effect, breaks allow-listing

14. OS Version & Compatibility#

OS VersionPcaCertificate SupportRootCertificate Support
Windows 10 1903+Full supportNot supported
Windows 10 1709–1809Full supportNot supported
Windows 11 21H2+Full supportNot supported
Windows Server 2019+Full supportNot supported
Windows Server 2022Full supportNot supported
Windows Server 2025Full supportNot supported

RootCertificate has never been supported in any version of WDAC or its predecessor (Device Guard / Code Integrity Policies). This is a design decision, not a version limitation.


15. Common Mistakes & Gotchas#

Mistake 1: Assuming RootCertificate Will Work Like Other Levels#

Wrong assumption: “I’ll add a RootCertificate rule for our enterprise root CA and all our signed software will be allowed.”

Reality: The rule is silently ignored. Software falls through to the default action, which in enforced mode means a block. This causes unexpected application failures that appear unrelated to WDAC.

Fix: Use PcaCertificate for the code-signing intermediate CA.

Mistake 2: Confusing the TBS Hash of Root vs. Intermediate#

Wrong approach: Extracting the thumbprint of the root CA and putting it in a <CertRoot Type="TBS"> element in a Signer rule.

Reality: WDAC Signer rules match against intermediate CA TBS hashes. Providing the root CA’s TBS hash will not match any file in the chain walk.

Fix: Walk the certificate chain and extract the TBS hash of the first intermediate CA (index 1 in the chain, not index 2 which is the root).

Mistake 3: Trying to Use RootCertificate to “Trust Everything” from a Vendor#

Wrong approach: Adding a root CA rule to create a blanket “trust this vendor” policy entry.

Reality: Even if it worked, it would trust far more than the vendor’s software — it would trust every certificate ever issued by that root’s entire PKI tree.

Fix: Identify the specific intermediate CA the vendor uses for code signing. Create a PcaCertificate rule for that specific intermediate. If you need further scoping, use Publisher (adds leaf CN) or FilePublisher (adds filename and version).

Mistake 4: No Error Message from WDAC Tooling#

The most dangerous aspect of attempting RootCertificate is the complete absence of error messages. PowerShell’s New-CIPolicy silently falls back. Direct XML authoring silently fails at runtime. Policy compilation succeeds. Only application failures reveal the problem, often in production.

Mitigation: Always review generated policy XML and verify that <Signer> elements reference intermediate CA (PCA) certificates, not root CA certificates. You can verify by cross-referencing the TBS hash against known root CA thumbprints.

Mistake 5: Believing RootCertificate Exists in WDAC Documentation#

Some older community blog posts and third-party documentation list RootCertificate as a valid level. This is incorrect for App Control for Business. The official Microsoft documentation explicitly lists the supported levels, and RootCertificate is not among them.


16. Historical Context#

Why Was RootCertificate Explicitly Excluded?#

When Microsoft designed Windows Defender Application Control (the predecessor to App Control for Business, first shipped in Windows 10 1607 as part of Device Guard), the engineering team considered the full spectrum of certificate-based trust levels.

The inclusion of a RootCertificate level was considered and explicitly rejected for the following reasons:

  1. Precedent from AppLocker: AppLocker, the predecessor policy system, had demonstrated that overly broad certificate trust led to policy bypasses. Administrators would trust a publisher’s root CA, and attackers would obtain legitimately-issued certs from that CA for their malware.

  2. Microsoft’s own PKI surface: If Microsoft’s own employees used RootCertificate to trust Microsoft’s root CA for Windows policy deployments, the policy would become essentially useless — it would allow any Microsoft-signed binary, including many that should not be present in a restricted environment.

  3. The PCA layer as the natural trust boundary: Microsoft’s PKI architecture already had a natural boundary at the PCA (Policy/Program Certificate Authority) level. Different PCAs are used for different purposes (OS signing, Authenticode, Azure, timestamping). Trusting at the PCA level allows meaningful segmentation of trust.

  4. Defense in depth: WDAC is designed as a defense-in-depth control. Making the broadest allowed level still meaningfully restrictive (PcaCertificate rather than RootCertificate) ensures that even broadly-scoped policies provide real security value.

The decision was never revisited because it proved correct: PcaCertificate-level rules provide sufficient coverage for virtually all real-world use cases while maintaining meaningful security boundaries.


17. Summary Table#

PropertyValue
Level NameRootCertificate
Supported in WDACNO — Not Supported
Why Not SupportedTrusts entire PKI subtree — catastrophically broad
What ci.dll DoesIgnores the rule / does not evaluate it
PowerShell BehaviorSilently falls back to PcaCertificate
XML Authoring BehaviorCompiles but fails to match at runtime
Correct AlternativePcaCertificate (broadest supported level)
Security RiskWould be the highest risk level if supported
Use CaseNone — never use this level
Decision RuleIf you want root-level trust → find the intermediate CA → use PcaCertificate
OS VersionsNever supported on any Windows version
Kernel Componentci.dll (Code Integrity)
Related LevelsPcaCertificate, Publisher, FilePublisher
DocumentationMicrosoft WDAC File Rule Levels reference (intermediate CA section)
WDAC File Rule Level: RootCertificate
https://mranv.pages.dev/posts/app-control-file-rule-level-rootcertificate/
Author
Anubhav Gain
Published at
2026-05-02
License
CC BY-NC-SA 4.0