AD CS ESC4 in 60 seconds

Active Directory Certificate Services (AD CS) uses templates to decide who may request a certificate, which identities that certificate may represent, and what it may be used for. ESC4 is not a special certificate type: it is write access that lets an insufficiently privileged principal turn a safe template into a dangerous one. ESC1 describes one dangerous result that write access can create; ESC4 is the permission failure that made the change possible.

The environment was clean.

Kerberoasting was closed — service accounts had long random passwords or gMSAs. AS-REP roasting returned nothing. LAPS was deployed and actually enforced, not just installed. Administrative tiering existed on the architecture diagram and, unusually, in the group memberships too. EDR was on every host, tuned, and someone was reading the alerts.

I have run out of easy paths in environments like this before. That is what they are for.

Then I looked at the certificate authority.

The environment was clean

The AD CS installation had never been assessed. Not assessed and risk-accepted — never examined at all. The domain had been hardened across years of remediation work, and the CA sitting inside that domain had been installed once, confirmed to issue certificates, and left alone ever since.

This is the pattern I keep running into, and it is not an accident of one environment.

The CA usually belongs to a different team than Active Directory. AD is owned by the identity or directory team. The CA is owned by PKI, or infrastructure, or whoever originally needed certificates for the wireless network eight years ago. Both teams are competent. Both teams are doing their jobs. Neither team believes the certificate templates are their problem.

That gap is not an administrative inconvenience. It is the vulnerability.

Security work follows ownership. When a team owns a system, that system accumulates review, hardening standards, change control, and someone who feels personally embarrassed when it is found wanting. When ownership is ambiguous, none of that accumulates — not because anyone decided to skip it, but because no one was ever the person whose job it was.

An AD CS installation in a mature domain is frequently the single largest concentration of unreviewed privilege in the environment. It can mint credentials for any identity in the forest. It is Tier 0 by function. And it is very often managed as though it were a print server.

ESC1 is the payload, ESC4 is the cause

Most published AD CS work starts from the same place: given a vulnerable certificate template, here is how you exploit it. The taxonomy — ESC1 through ESC16 — gets presented as a flat list of findings, each one a separate thing you might discover during enumeration.

That framing is why so many AD CS assessments stop one step short.

Recall what actually makes a template ESC1-shaped. Four conditions have to hold at once:

  • The requester supplies the subject. CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT is set in msPKI-Certificate-Name-Flag, so the certificate identifies whoever the requester says it does.
  • The certificate can be used to authenticate. The template carries an EKU permitting client authentication — Client Authentication, PKINIT Client Authentication, Smart Card Logon, or Any Purpose. A template with no EKU at all qualifies too.
  • A low-privileged principal can enroll. Enroll rights are granted to something broad enough to matter.
  • Nothing stands in the way. Manager approval is not required (CT_FLAG_PEND_ALL_REQUESTS unset in msPKI-Enrollment-Flag), and no authorised signatures are demanded (msPKI-RA-Signature is zero).

Four conditions. A template satisfying all four lets an unprivileged user request a certificate that says they are someone else, and then authenticate as that someone else.

Now consider ESC4, which is not a template configuration at all. ESC4 is write access over the template’s Active Directory objectWriteDacl, WriteOwner, WriteProperty, GenericWrite, GenericAll, or plain ownership.

Read those two paragraphs together and the relationship becomes obvious:

With ESC4, you do not need to find a template satisfying the ESC1 conditions. You set them yourself.

ESC4 does not sit alongside ESC1 in a list of findings. It sits above it. Write access to a template object collapses the entire escalation taxonomy into a single prerequisite, because every condition the taxonomy enumerates is a value you can now write. The enumeration question stops being is there a dangerous template here? and becomes can I make one?

This is the same shape as resource-based delegation: the payload is not a setting that was configured wrong — it is write access to an object that lets you create the setting. The template is an RBCD attribute one level up.

This is why a report line reading “ESC4 — one template has over-permissive ACLs — Medium” is one of the more expensive mistakes in AD CS assessment. The template’s current configuration is irrelevant. Its configuration is attacker-controlled.

CAUSE → ATTACKER-CONTROLLED CONFIGURATION → PAYLOAD → AUTH BOUNDARY template DACL ESC4 / WRITE root cause rewrite four gates subject · EKU · enroll safe → attacker-shaped ESC1 shape REQUEST CERT payload KDC mapping VALIDATE impact boundary WHAT EACH OBSERVATION MEANS enumeration effective write right exists proves ability, not impact controlled rewrite ESC4 becomes ESC1 proves config control authentication mapping accepted / rejected proves verified impact
ESC4 is the cause, ESC1 is a payload the attacker can manufacture, and certificate authentication is a separate boundary that must be tested rather than inferred. The diagram keeps capability, weaponisation, and verified impact from collapsing into one claim.

And once you are looking for write access rather than for misconfigured templates, you start seeing how these environments actually got this way.

How the misconfiguration is born

A vulnerable certificate template is almost never the result of someone configuring a template badly. In mature environments it is the residue of ordinary administration — five paths, in my experience, produce nearly all of it.

Template duplication

Nobody configures AD CS templates from scratch. You find the closest built-in template, duplicate it, and adjust. It is the documented workflow and the sensible one.

The duplicate inherits its security descriptor from the source, and whoever performs the duplication frequently ends up holding rights on the result. A template cloned by a helpdesk lead during a project years ago can still carry that lead’s access — or the access of a group they were in at the time — long after the project closed and the person changed roles.

The template looks correct. Its subject name settings are conservative. Its enrollment permissions are narrow. And a principal nobody has thought about since can rewrite all of it.

Delegation drift

Someone files a ticket asking to change a certificate’s validity period. The change is trivial and the request is legitimate. Rather than route every such request through the PKI team, an administrator grants the requesting group write access to the template so they can handle it themselves.

This is good operational judgement in isolation. Delegating routine changes to the team that makes them is how organisations scale.

The problem is that Active Directory has no permission meaning may edit the validity period. The available grant covers the whole object — including the subject name flags, the EKUs, the enrollment requirements, and the ACL itself. The delegation intended to cover one harmless field granted control over every field that matters.

Migration residue

Every AD CS installation of any age has been through at least one migration: a CA rebuild, a domain consolidation, a platform upgrade. Migrations run on service accounts with broad rights, because narrowing those rights mid-migration is how migrations fail at 3 a.m.

Migrations end. The service accounts rarely do. They stay enabled, stay privileged over the objects they touched, and stop appearing in anyone’s mental model of the environment because the project that created them is closed. The account is not in any current runbook. It is in the template’s ACL.

Nested group creep

A group is granted rights on a template. At the time, that group has four members and a clear purpose.

Then Active Directory does what Active Directory does. The group gets nested into a broader operational group during a reorganisation. That group gets nested into something broader still during the next one. Nobody re-examines the original grant, because from the template’s perspective nothing changed — the ACE still names the same group it always did.

The effective membership is now two orders of magnitude larger than the grant ever intended. This is the hardest of the five to catch by inspection, because the template’s ACL looks exactly as reasonable as the day it was written. The change happened somewhere else entirely.

Forgotten test grants

During a pilot, someone grants Authenticated Users or Domain Users write access to a template to eliminate permissions as a variable while debugging enrollment. Everyone has done a version of this.

The pilot succeeds. The grant is never reverted, because the thing that would prompt reverting it — enrollment failing — no longer happens.


What unites these five is the reason they survive in environments that are otherwise well defended:

None of them look wrong.

There is no misconfiguration to spot. There is a duplication performed according to Microsoft’s own guidance, a sensible delegation of routine work, a migration that completed successfully, a group nesting change made for good organisational reasons, and a debugging step that worked. Every individual decision was defensible when it was made, by someone competent, for a real reason.

They do not fail an audit checklist because they are not on it. They do not generate alerts because nothing anomalous happened. They do not appear in a vulnerability scan because no software is out of date. They are visible only if someone specifically enumerates certificate template ACLs and asks who can write to them — and in an environment where the CA has no clear owner, that someone does not exist.

Which is how a domain that closed Kerberoasting, deployed LAPS, enforced tiering, and tuned its EDR ends up one ACE away from an attacker minting a Domain Admin certificate.

The rest of this post shows exactly that, in a lab you can build yourself.

Building the lab

You do not need a domain to see this. You need a single Windows Server, promoted to a domain controller, with an Enterprise CA installed on the same box:

Install-ADDSForest -DomainName corp.local -DomainNetbiosName CORP -InstallDns -Force
Install-AdcsCertificationAuthority -CAType EnterpriseRootCA -CACommonName "corp-CA" -Force

Add one unprivileged user — a plain member of Domain Users, nothing more:

New-ADUser -Name "jdoe" -SamAccountName "jdoe" -UserPrincipalName "[email protected]" `
  -AccountPassword (ConvertTo-SecureString "Lab-Passw0rd!" -AsPlainText -Force) -Enabled $true

That is the whole environment. One VM, one low-privileged account, a certificate authority in its default state. Patch it fully — this matters for the last step of the chain, for reasons that will become clear.

The point of building it yourself, rather than reading a walkthrough, is that you introduce the misconfiguration by hand. Section three argued that these templates are born from ordinary administration. The lab is where you watch that happen, one delegation at a time, instead of taking my word for it.

So introduce it. Create a group standing in for a helpdesk team, and grant it write access to a template “so they can adjust validity periods” — the delegation drift from section three, reproduced deliberately:

$dn = "CN=CorpUser,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local"
$acl = Get-Acl -Path "AD:$dn"
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
  ([System.Security.Principal.SecurityIdentifier](Get-ADGroup "Helpdesk").SID),
  [System.DirectoryServices.ActiveDirectoryRights]::GenericWrite,
  [System.Security.AccessControl.AccessControlType]::Allow)))
Set-Acl -Path "AD:$dn" -AclObject $acl

One access control entry. Nothing about it looks like an attack.

The chain

From the attacker’s side — a Linux host with Certipy, holding only jdoe’s password — the environment is enumerated first:

certipy find -u [email protected] -p 'Lab-Passw0rd!' -dc-ip <DC> -vulnerable -stdout

Certipy reads each certificate template’s security descriptor and compares the principals that can write to it against the caller’s group memberships. Before the delegation, CorpUser is unremarkable and the scan says so. After it, the same command reports the template as ESC4 and names Helpdesk — a group containing jdoe — as a principal that can rewrite it. The value of running the scan twice, before and after, is that the difference is a single ordinary permission. That difference is the finding.

ESC4 is write access, and write access is not the payload — it is the means of producing one. The next command spends it. Certipy takes a backup of the template’s current configuration, then rewrites it to satisfy every ESC1 condition from section two — enrollee-supplies-subject, a client-authentication EKU, no approval:

certipy template -u [email protected] -p 'Lab-Passw0rd!' -dc-ip <DC> \
  -template CorpUser -save-configuration CorpUser-original.json \
  -write-default-configuration -force

Re-running certipy find now reports the same template as ESC1. This is the thesis made mechanical: the attacker did not search the environment for a vulnerable template and get lucky. They took a safe template they were allowed to edit and made it vulnerable, in one command, reversibly.

With an ESC1 template in place, the request is the textbook step. Ask the CA for a certificate, and because the template lets the enrollee supply the subject, ask for one that names a domain administrator:

certipy req -u [email protected] -p 'Lab-Passw0rd!' -dc-ip <DC> \
  -ca corp-CA -template CorpUser -upn [email protected]

The CA issues it. From its point of view nothing is wrong: the template permits enrollee-supplied subjects, jdoe has enroll rights, no approval is required. Every check passes because the template told it to pass them.

Where the modern environment fights back

The last step — turning that certificate into authentication — is where a fully patched 2025-era domain no longer behaves like the walkthroughs.

certipy auth -pfx administrator.pfx -dc-ip <DC>

Since the certificate-based authentication hardening in KB5014754 reached mandatory enforcement — the registry override was removed and compatibility mode retired in September 2025 — a domain controller will not authenticate a certificate on the strength of the UPN in its subject alternative name alone. It requires a strong mapping, most reliably the SID security extension the CA embeds in the certificate. And an Enterprise CA populates that extension with the SID of the account that requested the certificate — jdoe — not the administrator named in the SAN.

So the classic UPN-only ESC1 recipe, the one most published write-ups still show, is describing pre-September-2025 behaviour. On a patched domain the mismatch between the UPN and the embedded SID is exactly what strong mapping exists to reject.

This is why Certipy 5 added a -sid flag to req: it lets the request assert a target SID rather than inherit the requester’s. Whether an Enterprise CA honours an attacker-supplied SID on an ESC1 template is not a universal yes or no — it turns on the template and CA configuration, which is precisely the sort of thing that has to be tested against the specific environment rather than assumed from a blog post. That test is the reason this lab is worth building rather than reading about. What is not in doubt is the direction of travel: the ground under the standard ESC1 chain has moved, and an assessment that runs the 2023 recipe against a 2026 domain will draw the wrong conclusion about whether the finding is live.

Whatever the outcome, the template does not stay weaponised. The backup taken before the rewrite goes straight back:

certipy template -u [email protected] -p 'Lab-Passw0rd!' -dc-ip <DC> \
  -template CorpUser -write-configuration CorpUser-original.json -force

certipy find should now report ESC4 again but no longer ESC1. Leaving a weaponised template behind on a client’s CA converts an assessment into a liability; restoring it — and verifying the restore rather than assuming it — is not an afterthought. It is the part that separates a test from an incident.

REVERSIBLE VALIDATION — STATE, EVIDENCE, CLEANUP baseline ESC4 only backup hash config rewrite ESC1 window request issuance log restore close window verify ESC1 absent positive evidence DACL → changed attributes → issued certificate negative control + cleanup original hash restored → ESC1 no longer enumerates
The proof is not complete when a certificate is issued. It is complete when the original configuration is restored, the weaponised condition no longer enumerates, and the remaining ESC4 ACL is recorded as the root cause for remediation.

Evidence matrix

SignalWhat it provesNegative controlDefender verification
Effective template write right through a direct or nested principalThe caller can control security-relevant template attributes; this is ESC4 capabilityRemove the effective ACE in the lab and confirm the same rewrite is deniedExport template DACLs, expand nested membership, and review ownership as well as explicit write rights
Baseline-safe template enumerates as ESC1 only after the controlled rewriteWrite access can manufacture the vulnerable configuration instead of merely discovering oneRestore the saved configuration and confirm ESC1 disappears while ESC4 remainsCompare attribute-level before/after values and record event 5136 for each template change
The CA issues a certificate carrying the requested identity claimsThe modified template and enrollment policy accepted the requestSubmit the same request after restoration and expect denial or safe subject constructionCorrelate CA issuance records with requester, template, SAN, EKU, and approval state
Certificate authentication is accepted or rejected by strong mappingThe environment-specific impact boundary is verified, not assumedUse a mismatched SID/UPN control and expect the KDC to reject itValidate KDC mapping policy and authentication events separately from certificate issuance
Original configuration hash and enumeration result are restoredThe assessment did not leave the payload activeA final scan must show ESC4 only and no attacker-created enrollment conditionRe-export the template, compare against baseline, and retain the cleanup evidence with the finding

Why this never alerted

Walk back through the chain and ask, at each step, what a defender would have seen.

The rewrite that turned CorpUser into an ESC1 template was a modification to a directory object. Active Directory can record that as event 5136, but the audit subcategory that produces it — Directory Service Changes — is off in a default installation. The single most dangerous action in the entire chain, the one that manufactures the vulnerability, generates nothing unless someone turned that auditing on in advance. In an environment where the CA has no owner, nobody did.

The certificate request that followed is logged — the CA records issuance by default. But it records it as what it was: a successful, authorised enrollment against a template the requester was permitted to use. It looks identical to every legitimate certificate the CA issues, because at the moment of issuance it was legitimate. The template said so. An analyst scrolling issuance logs has no signal to catch on.

The auditing that would have caught the rewrite is one command to enable:

auditpol /set /subcategory:"Directory Service Changes" /success:enable
certutil -setreg CA\AuditFilter 127

With it on, the template modification surfaces as a 5136 naming the object, the attribute, and the account that made the change. Without it, the only durable trace of the whole chain is a certificate that looks exactly like all the others — and a window, between weaponising the template and restoring it, that can be measured in seconds.

Remediation that survives contact

The standard remediation line for ESC4 is “review and restrict certificate template permissions.” It is correct, and it is useless, because it does not say what to restrict them to, who is responsible for deciding, or how anyone would notice when they drift back.

Four things, in this order.

1. Inventory what can be written, and by whom

You cannot reason about a permission model you have never enumerated. Start read-only, from any domain-joined host with the AD module available:

$config = (Get-ADRootDSE).configurationNamingContext
$base   = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$config"

Get-ADObject -SearchBase $base -Filter { objectClass -eq "pKICertificateTemplate" } |
  ForEach-Object {
    $template = $_.Name
    (Get-Acl "AD:$($_.DistinguishedName)").Access |
      Where-Object {
        $_.AccessControlType -eq "Allow" -and
        $_.ActiveDirectoryRights -match "WriteDacl|WriteOwner|WriteProperty|GenericWrite|GenericAll"
      } |
      Select-Object @{ n = "Template"; e = { $template } }, IdentityReference, ActiveDirectoryRights
  } | Format-Table -AutoSize

Discount the principals you expect — Domain Admins, Enterprise Admins, SYSTEM. Everything left is your finding set.

Two things usually happen the first time a team runs this. The list is longer than anyone predicted, and at least one entry names a group nobody present can identify. Start with the second category, because an unidentifiable grant is by definition an unowned one.

Run it again after remediation and keep the output. It is your baseline, and without a baseline the next section is not enforceable.

2. Give the CA an owner

This is an organisational fix rather than a technical one, which is why it gets skipped — and why the technical fixes keep regressing when it is.

Someone has to be accountable for the AD CS installation: its templates, its permissions, and its presence in assessment scope. Not “the PKI team is aware of it.” Named, with the authority to refuse a delegation request.

Until that person exists, every other item on this list has a half-life. The delegation that produced the finding was granted for a real operational reason, and revoking the ACE does not remove the reason. It returns as a ticket, and the next administrator to receive it will make the same defensible decision the last one did.

3. Treat the CA as Tier 0 in practice, not on the diagram

Most tiering models place the CA in Tier 0 on paper. Far fewer administer it that way.

The test is not where the box sits in a diagram. It is whether the accounts that manage the CA are Tier 0 accounts, whether administration happens from privileged access workstations, whether CA administrators fall under the same controls as domain administrators, and whether the CA host itself is patched and monitored to the standard that tier demands.

If any of those answers is no, the CA is Tier 0 in classification and Tier 1 in practice. An attacker will engage with the practice.

4. Make template modification a monitored event

Certificate template objects change rarely, and always for reasons known in advance. That combination makes them close to an ideal detection target: a low-volume, high-signal event class a mature environment can alert on directly rather than merely log.

The modification is also the earliest moment any of this becomes visible. By the time a certificate is issued, the window is already open — and the request itself will look entirely legitimate, because it is. The template said it was allowed.

The CA is Tier 0 whether you treat it as one or not

The finding in this post was not a vulnerability in AD CS. Every component behaved exactly as documented. A group held write access to a template, and write access to a template means control over what that template asserts. The product worked. The permission model worked. The certificate authority issued a certificate to a requester who was, by the template’s own configuration, entitled to ask for one.

What failed was ownership. A system capable of minting credentials for any identity in the forest sat between two competent teams, and neither one’s remit quite covered it. Every individual decision that led there was defensible. The absence of anyone whose job it was to look at those decisions collectively is what turned them into a finding.

None of this is specific to certificate services. Any system that accumulates privilege faster than it accumulates scrutiny arrives at the same place — and the systems most likely to do that are precisely the ones sitting on a boundary between two teams, working correctly, for years.

The CA is Tier 0 whether you treat it as one or not. The only variable is who finds out first.

Sources & freshness

How current is this note?

Sources checkedMarch 12, 2026

The latest source-review, content-update, or publication date is shown.

ReviewAuthor review complete

The author completed a technical review. This does not, by itself, claim lab reproduction.