Kerberos misconfigurations are some of the longest-running risks in any AD environment. Unconstrained delegation on a single member server hands a domain admin TGT to anyone who compromises it. Duplicate SPNs silently break authentication for half a department. AS-REP roasting turns any account with DONT_REQ_PREAUTH into an offline-crackable hash. None of these show up in routine reports.
This guide audits all three from PowerShell and ships the Dargslan.KerberosAudit module plus a free PDF cheat sheet.
Table of Contents
Step 1: Unconstrained delegation
An account with the Trusted for Delegation flag (UAC bit 0x80000 = 524288) caches the TGT of every user that authenticates to it. Compromise that account and you have credentials for every user who ever connected. The LDAP filter is the standard one:
Get-ADComputer -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' `
-Properties OperatingSystem | Select Name, OperatingSystem
Get-ADUser -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' |
Select SamAccountName
Defensible target: ≤ 1 (the domain controllers themselves are exempt). Anything else needs a justification or replacement with constrained delegation.
Step 2: Constrained + RBCD
Constrained delegation (msDS-AllowedToDelegateTo) and Resource-Based Constrained Delegation (msDS-AllowedToActOnBehalfOfOtherIdentity) are the modern alternatives. They are not findings on their own — but you should know which accounts have them so you can verify the target services are still in scope:
Get-ADObject -LDAPFilter '(|(msDS-AllowedToDelegateTo=*)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))' `
-Properties msDS-AllowedToDelegateTo, msDS-AllowedToActOnBehalfOfOtherIdentity, sAMAccountName
Step 3: Duplicate SPNs
Two accounts owning the same SPN means Kerberos cannot decide which key to use, so authentication breaks intermittently in ways that look like network problems:
$all = Get-ADObject -LDAPFilter '(servicePrincipalName=*)' `
-Properties servicePrincipalName, sAMAccountName |
ForEach-Object {
$n = $_.sAMAccountName
$_.servicePrincipalName | ForEach-Object {
[pscustomobject]@{ SPN = $_; Account = $n }
}
}
$all | Group SPN | Where Count -gt 1
Fix with setspn -X (find duplicates) and setspn -D <spn> <account> (delete from the wrong owner).
Step 4: AS-REP roastable accounts
DONT_REQ_PREAUTH (UAC bit 0x400000 = 4194304) lets an attacker request a Kerberos AS-REP without proving knowledge of the password — and crack it offline. It should never be set on a real user account:
Get-ADUser -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=4194304)' |
Select SamAccountName, Enabled
A pragmatic PASS / WARN / FAIL score
- ≤ 1 unconstrained-delegation account (1 pt)
- 0 duplicate SPNs (1 pt)
- 0 AS-REP roastable accounts (1 pt)
3/3 PASS, 1-2 WARN, 0 FAIL.
Dargslan.KerberosAudit module
Install-Module Dargslan.KerberosAudit -Scope CurrentUser
Import-Module Dargslan.KerberosAudit
Export-DargslanKerberosAuditReport -OutDir C:\reports
FAQ
What about Kerberoasting?
Any account with an SPN can be Kerberoasted; the protection is a strong password (long, random, gMSA where possible). The audit does not score that — review the SPN owner list manually.
Does this need Domain Admin?
No — every cmdlet uses LDAP read against the directory.
Cheat sheet?
Free PDF at /cheat-sheets/kerberos-delegation-audit-2026.