Policy design11 min read

Choosing App Control rule levels, and using version rules properly

Every rule level with its real trade off, why hash rules break every patch, and how a minimum version turns App Control into patch enforcement as well.

Updated 26 May 2026

Choosing the rule level is the decision that determines whether your policy still works after the next patch cycle. It gets made quickly, often by whatever the tooling defaulted to, and the cost of getting it wrong arrives months later as a maintenance burden nobody budgeted for.

Here is what each level actually gives you.

The levels, from broadest to most exact

PcaCertificate adds the highest available certificate in the provided chain. Typically one certificate below the root, because the scan does not resolve the full chain through local root stores or an online check. Broadest thing you can express.

Publisher combines the PcaCertificate level with the common name of the leaf certificate. Microsoft's own framing is that you use it to trust a certificate issued by a particular certificate authority and issued to a specific company you trust. This is where most rules should sit.

LeafCertificate adds trust at the individual signing certificate level. New versions of a product usually keep the same signing certificate, so no policy update is needed when the product updates. The catch is that leaf certificates have shorter validity periods than other certificate levels, so the policy needs updating whenever they change.

SignedVersion combines the publisher rule with a version number. Allows anything from that publisher at or above the version you specify.

FilePublisher combines the file name attribute of the signed file, the publisher, and a minimum version number. Trusts specific files from a specific publisher at or above a version.

FileName specifies the original filename. Hash values change on update, filenames usually do not, so it survives updates without a policy change. Less specific security than a hash. By default it uses the OriginalFileName attribute from the file's resource header.

FilePath allows binaries to run from specific locations. User mode binaries only, and it cannot be used to allow kernel mode drivers.

Hash specifies individual Authenticode image hash values. The most specific level available, and the one that requires the most maintenance, because every update changes the hash.

For kernel binaries there are WHQL, WHQLPublisher and WHQLFilePublisher, which are the same ideas layered on top of a requirement that the binary was submitted to Microsoft and signed by the Windows Hardware Qualification Lab.

RootCertificate is listed as not supported. Do not build a plan around it.

Version rules are the underused capability

Most teams treat App Control as a yes or no question about an application. It can express something more useful than that, and this is the part worth reading twice.

Both FilePublisher and SignedVersion take a version number, and the semantics are precise. In the policy XML these appear as MinimumFileVersion and MaximumFileVersion, and the behaviour is:

  • Minimum only, on an allow rule. Files with a version greater than or equal to the specified version are allowed.
  • Minimum only, on a deny rule. Files with a version less than or equal to the specified version are blocked.
  • Maximum only, on an allow rule. Files with a version less than or equal to the specified version are allowed.
  • Both specified. For allow rules, files between the two inclusive are allowed. For deny rules, files between the two inclusive are denied.

The practical consequence: an allow rule at FilePublisher level with a minimum version means the current build of an application runs and older builds stop matching that rule.

That is patch enforcement expressed through execution control. You are not asking people to update. You are declining to run the version you are trying to retire. For a browser or a widely deployed client with a known vulnerable release, that is a considerably stronger position than a compliance report saying 87 per cent of the fleet has patched.

Not matching an allow rule is not the same as being denied

This is the part that catches people, and it is worth being precise about because it decides whether the technique works at all.

Raising the minimum version on an allow rule removes one reason the old build was allowed. It does not deny it. If anything else on the device authorises that file, it still runs, and the version floor never comes into it. Three things commonly do:

  • Managed installer origin. If your deployment tool installed the application, its files were tagged as it wrote them. Microsoft is explicit that with the managed installer option enabled, "as long as there are no deny rules for the binary, App Control will allow it to run based purely on its managed installer origin". The old Chrome build your deployment tool put there is authorised by how it arrived, not by its version.
  • The Intelligent Security Graph. A widely deployed browser build is exactly the kind of file the ISG considers known and good, including the one you are trying to retire.
  • Another allow rule, or another base policy. Anything broader, a signer or certificate authority rule for the same vendor, allows it independently.

If you want an old version to stop running, use a deny rule with a maximum version, in the base policy. Deny is evaluated first and beats everything, including managed installer origin, ISG and any allow rule anywhere. That is the only construction that guarantees the outcome.

So the complete version pinning pattern is two rules: an allow rule with a minimum version for what you want running, and a deny rule with a maximum version for what you want stopped. Teams that write only the first one and see the old build still executing usually conclude version rules do not work, when what happened is that something else was answering the question.

Two more things to be careful about before you reach for it.

It depends on the version metadata being correct in the signed file, because that is what the rule matches on.

Somebody has to move the floor when the fleet moves. Raise the minimum faster than your deployment rings can deliver the new build and you have stopped people working mid update. The rule is only as good as the process that maintains it, which is the same thing that is true of hash rules, just with better failure characteristics.

Why hash rules become the maintenance problem

A policy full of hash rules looks correct on the day it is created and starts blocking things the following patch cycle. That much is obvious. Two details are less obvious.

App Control uses the Authenticode image hash, not a flat file hash. The Authenticode calculation omits the file's checksum, the certificate table and the attribute certificate table. So the hash does not change when signatures or timestamps are altered, or when a signature is removed. That is genuinely helpful: you do not need to revise hash rules because a file was re-signed.

A scan produces four hash rules per file, and sometimes eight. The cmdlets precalculate an Authenticode SHA1 hash, SHA256 hash, SHA1 page hash and SHA256 page hash, because which one App Control uses during validation depends on how the file is signed and how it is being loaded. Page hash signed files are validated per page, avoiding loading the whole file into memory. Rather than predict which applies, all four are included.

Eight appears when the cmdlets cannot determine whether a file runs only in user mode or only in the kernel, so rules are created for both signing scenarios. If you know a file only loads in one, the extra rules can be safely removed.

There is also a rare case where a file's format does not conform to the Authenticode specification and App Control falls back to the flat file hash. You can spot it: the hash in the correlated 3089 event matches the flat file hash rather than the Authenticode one. Rules for those files have to be created against the flat hash.

File path rules, and the check that protects them

Path rules are the option people reach for when nothing else works, so it is worth knowing exactly what they are worth.

Microsoft is unambiguous: path rules "don't provide the same security guarantees that explicit signer rules do, since they're based on mutable access permissions". They are best suited to environments where most users run as standard rather than administrator, and to paths you expect to remain administrator writeable only.

By default App Control performs a runtime user-writeability check, which confirms that current permissions on the path only allow write access for administrators. That check is doing real work. Without it, a path rule over a directory a standard user can write to is an open door.

There is a wrinkle. App Control recognises a defined list of well known administrator SIDs. If a path grants write permission to any SID outside that list, the path is treated as user writeable even if that SID belongs to a custom administrator account. Option 18 Disabled:Runtime FilePath Rule Protection overrides the check, and should be understood as switching off the thing that made path rules defensible rather than as a compatibility setting.

One related quirk worth knowing if you are on older platforms: MSI installer files are always detected as user writeable on Windows 10, and on Windows Server 2022 and earlier. Allowing MSI files by path on those versions requires option 18.

Wildcards, and what changed

Wildcard support depends on the platform, which catches people writing one policy for a mixed estate.

* matches zero or more characters and works on Windows 10, Windows 11 and later, and Windows Server 2022 and later. ? matches a single character and requires Windows 11 and later, or Windows Server 2025 and later.

The placement rule is the one that bites. On Windows 11 you can use one or more wildcards anywhere in a path rule. On every other Windows and Windows Server version, only one wildcard is allowed per rule and it must be at the beginning or the end.

The macros %OSDRIVE%, %WINDIR% and %SYSTEM32% handle a varying volume letter and can be combined with wildcards.

Microsoft documents a worked example of why mid-path wildcards deserve care. Given a rule matching a pattern in the Configuration Manager cache directory, both of these paths match:

C:\WINDOWS\CCMCACHE\12345\setup????-x64.exe
C:\USERS\someone\Downloads\CCMCACHE\Bad\setuphaha-x64.exe

If you have also disabled the administrator writeability check, that second path is authorised.

Without a wildcard, a path rule allows exactly one file.

The limitation that explains a lot of mystery blocks

App Control signer rules only work with RSA cryptography, at a maximum key length of 4096 bits. ECC algorithms such as ECDSA are not supported.

When a file is blocked for this reason, the correlated 3089 signature event shows VerificationError = 23. That is the tell. The signer rule looks correct, the certificate looks correct, and the file is still refused.

The options are to allow the file by hash or file attribute rules instead, or by another signer rule if the file also carries an RSA signature. It is worth checking for this before concluding a signer rule is malformed.

Choosing, in practice

The pattern that survives contact with a real estate:

Publisher for almost everything. Signed software from vendors you have decided to trust, at a level that survives their updates.

FilePublisher with a minimum version where you want to retire old builds of something specific, or where a publisher signs more than you want to trust.

Managed installer for the long tail, so that what your deployment tool installs is trusted by how it arrived rather than by enumerating it. That moves the trust decision into your existing software approval process.

Hash only where nothing better exists, which in practice means unsigned software, with an owner named for reissuing the rule and a written reason it is unsigned. The better long term answer is signing it internally, and the best one is asking the vendor at renewal.

Path rules as a last resort, over a directory you have confirmed is administrator writeable only, with the runtime check left on.

The primary level is set with -Level on New-CIPolicy, and -Fallback covers binaries that cannot be trusted by the primary criteria. Publisher with a hash fallback is the combination Microsoft's own example uses, and it is a reasonable starting point: trust the signed estate by publisher, catch the unsigned remainder by hash, then look at what landed in the fallback pile and treat that list as work rather than as a finished policy.

That list is usually the real output of a first policy build. The platform covers where it fits, and what App Control covers is the shorter introduction if you are earlier than this.

Choosing the level is a judgement, and the judgement needs a record. PoliEze keeps the reason for each rule with the rule, in readable terms rather than raw XML, so an approver can see what changed, at which level, and why that level was chosen. That record is also what makes the choice defensible a year later, when the person who made it has moved on.

Sources

Questions about this

Can App Control block an old version of an application?
Yes, but it takes two rules. An allow rule with MinimumFileVersion permits that version or newer, which stops an older build matching that rule. It does not deny it, so if the file is authorised another way, by managed installer origin, by the Intelligent Security Graph or by a broader signer rule, it still runs. To stop an old version you also need a deny rule with MaximumFileVersion in the base policy, because deny is evaluated first and beats all of those.
Why does a policy scan create four hash rules for one file?
Because App Control precalculates an Authenticode SHA1 hash, SHA256 hash, SHA1 page hash and SHA256 page hash. Which one gets used depends on how the file is signed and how it is being loaded, so all four are included rather than guessing.
Are file path rules safe to use?
Only where the directory is genuinely write protected. Microsoft states path rules do not provide the same guarantees as signer rules because they are based on mutable access permissions, and they are best suited to environments where most users run as standard rather than administrator.
Why is my file not allowed even though I added its signer?
One common cause is elliptic curve cryptography. App Control signer rules only work with RSA, and ECDSA is not supported. A file blocked for that reason shows VerificationError equals 23 on the correlated 3089 event.

Related reading

Stuck on the thing this article describes?

If you are working through this on a real fleet and it is not going the way the documentation suggests, that is the conversation we are best at. Send us the block events.