AD-INV-005: Templates published outside the declared list¶
medium Invariants Reads: LDAP
A certificate template is published on an enterprise CA but is not in the declared list, so the CA issues certificates nobody approved.
Why it matters¶
Each published template is an issuance path. Templates are often published for a test or a single project and never removed; later someone edits one, or its enrollment rights widen, and it becomes an ESC1-style path to the domain (AD-ADCS-001). Keeping the published set to a reviewed list shrinks what the ESC checks have to catch, and makes a template published by an attacker with ManageCA rights stand out.
How ad-doctor detects it¶
Runs only with --invariants FILE that has a [templates] section:
A template counts as published when its name appears in certificateTemplates of any
enrollment service under CN=Enrollment Services,CN=Public Key Services,CN=Services in
the configuration partition. Names are compared, ignoring case, with published; each
extra template is one object, for example LabESC1.
Attributes and probes read
certificateTemplates (on each enrollment service)cn of each pKICertificateTemplate
Severity¶
Always medium. An unexpected template is not exploitable by itself; the ESC checks report it at their own severity when it is.
False positives and limits¶
- Templates published by product installs (for example
DomainControllerAuthentication,KerberosAuthentication,DirectoryEmailReplicationon a CA set up for domain controllers) are expected in many domains. Add the ones you use topublished.
Fix¶
-
List the published templates on each CA:
-
Unpublish the templates nobody needs. Existing certificates stay valid; nothing new can be issued from the template:
-
For templates that stay, review their enrollment rights and flags with the ESC checks before adding them to
published. -
If the template is intended, add it to
publishedin a reviewed change; see Invariants.
Verify¶
ad-doctor scan dc01.corp.example --ldaps -u 'CORP\auditor' --invariants invariants.toml --only AD-INV-005
To accept the risk instead, add an entry to the file passed with --accept (see accepted risks):
[[accept]]
check = "AD-INV-005"
objects = ["..."] # optional; without it the whole check is accepted
reason = "..."
expires = 2027-03-31
Related checks¶
References¶
Microsoft and vendors
Research
Available since 0.1.0.