Introduction
Active Directory allows groups to contain other groups, enabling flexible role-based access control. However, if Group A contains Group B, and Group B contains Group A (directly or through a chain of nested groups), AD group membership enumeration enters an infinite loop. This causes login timeouts, token generation failures, and application authorization errors when the application tries to resolve the full group membership chain.
Symptoms
- Login takes 30+ seconds and eventually times out
- Application logs show:
`- LDAP error: Operations error - Circular group nesting detected
`- Or in Windows Event Log:
`- Event ID 4624: An account was successfully logged on.
- However, the token generation took excessive time due to group enumeration.
`whoami /groupshangs or shows incomplete group list- Application authorization check fails:
`- Error: Maximum group nesting depth exceeded (1000)
`
Common Causes
- Admin accidentally adds Group A to Group B and Group B to Group A
- Complex group nesting across multiple OUs creates indirect circular references
- Migration tools create circular references during group restructuring
- Automated group management scripts create bidirectional membership
- AD token size exceeds Kerberos max token size (48 KB) due to deep nesting
Step-by-Step Fix
- 1.Detect circular group nesting using PowerShell:
- 2.```powershell
- 3.# Find direct circular references
- 4.function Find-CircularGroupNesting {
- 5.$groups = Get-ADGroup -Filter * -Properties Members, memberOf
- 6.foreach ($group in $groups) {
- 7.foreach ($member in $group.Members) {
- 8.$memberGroup = Get-ADGroup -Identity $member -ErrorAction SilentlyContinue
- 9.if ($memberGroup -and $memberGroup.memberOf -contains $group.DistinguishedName) {
- 10.Write-Host "Circular reference: $($group.Name) <-> $($memberGroup.Name)"
- 11.}
- 12.}
- 13.}
- 14.}
- 15.Find-CircularGroupNesting
- 16.
` - 17.Check token size for affected users:
- 18.```powershell
- 19.# Estimate Kerberos token size for a user
- 20.function Get-UserTokenSize {
- 21.param([string]$Username)
- 22.$user = Get-ADUser -Identity $Username -Properties memberOf
- 23.$groups = $user.memberOf
- 24.$estimatedSize = ($groups.Count * 40) + 1200
- 25.Write-Host "User: $Username"
- 26.Write-Host "Group count: $($groups.Count)"
- 27.Write-Host "Estimated token size: $estimatedSize bytes (max: 49152)"
- 28.if ($estimatedSize -gt 48000) {
- 29.Write-Warning "Token size approaching Kerberos limit!"
- 30.}
- 31.}
- 32.Get-UserTokenSize -Username "jdoe"
- 33.
` - 34.Remove the circular reference:
- 35.```powershell
- 36.# Remove GroupA from GroupB's membership to break the cycle
- 37.Remove-ADGroupMember -Identity "GroupB" -Members "GroupA" -Confirm:$false
# Verify the circular reference is broken Get-ADGroupMember -Identity "GroupA" -Recursive | Select-Object Name Get-ADGroupMember -Identity "GroupB" -Recursive | Select-Object Name ```
- 1.Use AD Administrative Center to visualize nesting:
- 2.```powershell
- 3.# Export group membership for analysis
- 4.Get-ADGroup -Filter {Name -like "App_*"} -Properties Members, memberOf |
- 5.Select-Object Name,
- 6.@{N='Members';E={$_.Members -join '; '}},
- 7.@{N='MemberOf';E={$_.memberOf -join '; '}} |
- 8.Export-Csv -Path "group-nesting.csv" -NoTypeInformation
- 9.
` - 10.Open the CSV in Excel and use conditional formatting to highlight circular references.
- 11.Implement MaxTokenSize registry fix for large groups (temporary workaround):
- 12.```powershell
- 13.# On the affected server (NOT a long-term solution)
- 14.Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters" `
- 15.-Name "MaxTokenSize" -Value 65535 -Type DWord
# Reboot required Restart-Computer ```
- 1.Prevent future circular references with a validation script:
- 2.```powershell
- 3.# Run before adding group membership
- 4.function Test-GroupNestingSafe {
- 5.param([string]$ParentGroup, [string]$ChildGroup)
# Check if adding ChildGroup to ParentGroup would create a cycle $descendants = Get-ADGroupMember -Identity $ChildGroup -Recursive | Where-Object { $_.objectClass -eq 'group' }
if ($descendants.DistinguishedName -contains (Get-ADGroup $ParentGroup).DistinguishedName) { Write-Error "Adding '$ChildGroup' to '$ParentGroup' would create a circular reference!" return $false } return $true }
# Use before adding membership: if (Test-GroupNestingSafe -ParentGroup "IT-Admins" -ChildGroup "Server-Admins") { Add-ADGroupMember -Identity "IT-Admins" -Members "Server-Admins" } ```
Prevention
- Validate group membership changes with the
Test-GroupNestingSafescript - Keep group nesting depth to 3 levels or fewer
- Monitor Kerberos token sizes for users with many group memberships
- Use AD schema attribute
tokenGroupsfor efficient group resolution - Implement change management approval for group nesting modifications
- Run periodic audits with
Find-CircularGroupNestingscript