Remediation Guides

AdminSDHolder Permissions: How to Remove Suspicious Access Rights and Force SDProp

26 September 2026 8 min read

An AdminSDHolder permissions finding means a non-privileged user, group or service account holds an access control entry (ACE) on CN=AdminSDHolder,CN=System, the template ACL that SDProp copies onto Domain Admins and every other protected account. Fix it by removing that entry with ADSI Edit or dsacls /R, then run SDProp so the change reaches the protected objects.

Check the related dSHeuristics setting in the same pass. One character in that attribute can switch the protection off for four built-in operator groups.

What the scanner is actually detecting

This is a permissions finding on a single directory object, not a missing patch. Both tools read the ACL of CN=AdminSDHolder,CN=System,DC=contoso,DC=com and compare it with what an administrative-only template should contain.

Scanner Finding title What it checks
Microsoft Defender for Identity (security posture assessment in Secure Score) Remove access rights on suspicious accounts with the Admin SDHolder permission Non-sensitive accounts that hold permissions on the AdminSDHolder object.
Tenable Identity Exposure Ensure SDProp Consistency (Critical indicator of exposure) Whether the AdminSDHolder ACL allows privileged access only to administrative accounts.

PingCastle covers two neighbouring conditions: “Ensure that the AdminSDHolder protection has not been disabled for some critical groups” (the dSHeuristics check below) and “Ensure that Exchange did not modify the AdminSDHolder object to introduce vulnerabilities”.

Why the object matters: SDProp runs every 60 minutes by default on the domain controller holding the PDC emulator role. It compares the security descriptor of every protected account and group with AdminSDHolder and overwrites any that differ. The protected set includes Administrators, Domain Admins, Enterprise Admins, Schema Admins, Account Operators, Server Operators, Print Operators, Backup Operators, Replicator, Domain Controllers, Read-only Domain Controllers, Key Admins, Enterprise Key Admins, the built-in Administrator and krbtgt, and the direct or nested members of the protected groups.

Real-world risk

Any ACE on AdminSDHolder ends up on every protected object within about an hour. Reset Password on the template lets the holder reset Domain Admin passwords. Full Control, WriteDacl or write access to the member attribute lets it add itself to privileged groups. Removing the entry from Domain Admins directly does not help, because SDProp puts it back on the next cycle. Tenable maps this indicator to MITRE ATT&CK T1098 (Account Manipulation) under the Persistence tactic.

The limits are worth stating. An attacker first needs control of the principal named in the ACE. Many real hits are old delegations for a helpdesk group, a password vault or a sync tool, not an intrusion, and a read-only entry is far less dangerous than one that can write or reset passwords. But an unexplained write entry on this object should be treated as a possible backdoor until you know who added it.

How to confirm it on the host

Run these on a domain controller or a management host with the Active Directory PowerShell module. Replace the DN with your own.

dsacls "CN=AdminSDHolder,CN=System,DC=contoso,DC=com"

The PowerShell view is easier to sort and filter:

Import-Module ActiveDirectory
$domainDN = (Get-ADDomain).DistinguishedName
$path = "AD:CN=AdminSDHolder,CN=System,$domainDN"
$acl  = Get-Acl -Path $path
$acl.AreAccessRulesProtected   # expected: True (inheritance disabled)
$acl.Access | Sort-Object IdentityReference |
    Format-Table IdentityReference, AccessControlType, ActiveDirectoryRights, ObjectType -AutoSize

Expect SYSTEM, the built-in administrative groups and a few narrowly scoped entries that ship with the domain. The reliable way to know what “default” looks like for your Windows Server version is to dump AdminSDHolder in a clean lab domain and diff the two outputs. Anything else, especially with GenericAll, GenericWrite, WriteDacl, WriteOwner, WriteProperty or ExtendedRight, is what the scanners are reporting.

Confirm the entry has already been stamped onto a protected group (Domain Admins is RID 512):

$da = Get-ADGroup -Identity "$((Get-ADDomain).DomainSID.Value)-512"
(Get-Acl -Path "AD:$($da.DistinguishedName)").Access |
    Where-Object { $_.IdentityReference.Value -eq 'CONTOSOsvc-helpdesk' }

Find out when the ACL last changed and on which DC:

repadmin /showobjmeta DC01 "CN=AdminSDHolder,CN=System,DC=contoso,DC=com"

Look at the nTSecurityDescriptor row. Finally, read the 16th character of dSHeuristics (dwAdminSDExMask):

$cfg  = (Get-ADRootDSE).configurationNamingContext
$dsDN = "CN=Directory Service,CN=Windows NT,CN=Services,$cfg"
$h = (Get-ADObject $dsDN -Properties dSHeuristics).dSHeuristics
if ($h -and $h.Length -ge 16) { "dwAdminSDExMask = $($h[15])" } else { "not set (0)" }

Anything other than 0 excludes groups from protection. The value is a hex sum: 1 is Account Operators, 2 is Server Operators, 4 is Print Operators and 8 is Backup Operators, so a means Server Operators and Backup Operators are excluded.

How to fix it

Back up the current ACL

dsacls "CN=AdminSDHolder,CN=System,DC=contoso,DC=com" > C:Tempadminsdholder-before.txt
(Get-Acl -Path $path).Sddl | Out-File C:Tempadminsdholder-before.sddl

Option 1: ADSI Edit

This is the procedure Microsoft documents for the Defender for Identity assessment:

  1. Open ADSI Edit and connect to the Default naming context on a domain controller.
  2. Browse to CN=System > CN=AdminSDHolder and open its properties.
  3. Select Security > Advanced and remove the entries for the principals listed as exposed in the assessment.
  4. Apply the change.

Option 2: dsacls, remove every entry for a principal

dsacls "CN=AdminSDHolder,CN=System,DC=contoso,DC=com" /R CONTOSOsvc-helpdesk

/R deletes all ACEs for that user or group on the object. Do not use /S here: it resets the object to the schema default for its object class, which is not the same as the AdminSDHolder template.

Option 3: PowerShell, targeted removal

Use this when a principal is listed by name and you want to leave everything else untouched. Run it in the session from the confirm step so $path is set:

$acl = Get-Acl -Path $path
$target = 'CONTOSOsvc-helpdesk'
$aces = @($acl.Access | Where-Object { $_.IdentityReference.Value -eq $target })
foreach ($ace in $aces) { $acl.RemoveAccessRuleSpecific($ace) }
Set-Acl -Path $path -AclObject $acl

Push the change out: run SDProp now

Protected objects keep the old entry until SDProp runs. You can wait up to 60 minutes, or trigger it on the PDC emulator. Microsoft’s documented method uses Ldp.exe: connect and bind to the PDC emulator, open Browse > Modify, leave DN blank, set attribute RunProtectAdminGroupsTask to 1, then Enter and Run. The protocol specification gives the same operation as LDIF. Save this as C:Tempsdprop.ldf:

dn:
changetype: modify
add: runProtectAdminGroupsTask
runProtectAdminGroupsTask: 1
-

Then import it against the PDC emulator:

$pdc = (Get-ADDomain).PDCEmulator
ldifde -i -f C:Tempsdprop.ldf -s $pdc

The request only has an effect on the PDC emulator, and the account must hold the Run-Protect-Admin-Groups-Task right on the domain root.

Reset dwAdminSDExMask if it is not 0

dSHeuristics sits in the configuration partition, so it affects the whole forest and normally needs Enterprise Admin rights. Change only the 16th character and keep the rest of the string as it is:

$h | Out-File C:Tempdsheuristics-before.txt
$new = $h.Substring(0,15) + '0' + $h.Substring(16)
Set-ADObject $dsDN -Replace @{dSHeuristics = $new}

Then investigate

Use the repadmin timestamp and your change records to find out who added the entry. If the principal is unexpected and has write rights, review what it did with privileged accounts after that date. For the wider domain controller baseline, see the Windows Server hardening checklist, and for credential theft on the same tier 0 systems, the guide to LSASS protection with Credential Guard and RunAsPPL.

How to verify the fix and rescan

Run the dsacls or Get-Acl check again on AdminSDHolder, then on Domain Admins after SDProp has run. The removed principal should be gone from both. Re-read dSHeuristics and confirm the 16th character is 0 or not set. No reboot is needed.

In Defender for Identity, the exposed entity list updates within minutes, but scores and statuses refresh every 24 hours, so the recommendation may stay open for a day. In Tenable Identity Exposure, confirm the principal no longer appears under Ensure SDProp Consistency.

What can break and how to roll back

  • Password reset delegation for admin accounts. A helpdesk group or password vault that resets privileged passwords through the template loses that ability after the next SDProp cycle.
  • Microsoft Entra Connect password writeback for protected accounts. The ADSyncConfig cmdlets accept -IncludeAdminSdHolders, and Microsoft’s documentation says this isn’t recommended. Removing the entry stops writeback for protected accounts only.
  • Old Exchange permissions. PingCastle notes that older Exchange installs granted the Exchange Windows Permissions group rights over protected objects, and that newer versions no longer do. Test Exchange administration after removal.

To roll back, restore only the DACL from the saved SDDL, then run SDProp again:

$acl = Get-Acl -Path $path
$acl.SetSecurityDescriptorSddlForm((Get-Content C:Tempadminsdholder-before.sddl -Raw).Trim(),
    [System.Security.AccessControl.AccessControlSections]::Access)
Set-Acl -Path $path -AclObject $acl

For dSHeuristics, write the saved string back with the same Set-ADObject -Replace command.

Common false positive reasons

  • A deliberate tier 0 delegation. The account is meant to manage admin accounts, but the scanner does not know that. Either move it into proper admin tiering or document it as an accepted exception.
  • Orphaned SIDs. Entries for deleted accounts show as raw S-1-5-21 SIDs. They grant nothing today, but remove them anyway.
  • Lab-versus-production differences. A default entry for your Windows Server version may look unfamiliar. Compare with a clean lab baseline before removing it.
  • Stale results. Defender for Identity status lags up to 24 hours behind the directory.

FAQ

How often does SDProp run?

Every 60 minutes by default, on the PDC emulator. The AdminSDProtectFrequency value under HKLMSYSTEMCurrentControlSetServicesNTDSParameters accepts 60 to 7200 seconds, but Microsoft advises against lowering it in production because of LSASS load.

Why do permissions I set on a Domain Admin keep disappearing?

SDProp overwrites them with the AdminSDHolder ACL. That is the protection working as designed.

Can I add a deny entry instead of removing the allow entry?

Remove the allow entry. A deny on the template spreads to every protected object and is harder to audit later.

Does removing a user from Domain Admins clear adminCount?

No. The account keeps adminCount set to 1 and its hardened ACL, which is why PingCastle lists such accounts separately.

Tracking this finding across many hosts

AdminSDHolder findings come from identity tools rather than host scans, and the same entry often shows up in more than one of them. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners and merges duplicates within each scanner, not across scanners, so one ACE reported by two tools stays as two records. Its AI triage can suggest a false positive with evidence, but a person makes the decision.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing