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 /groups hangs 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. 1.Detect circular group nesting using PowerShell:
  2. 2.```powershell
  3. 3.# Find direct circular references
  4. 4.function Find-CircularGroupNesting {
  5. 5.$groups = Get-ADGroup -Filter * -Properties Members, memberOf
  6. 6.foreach ($group in $groups) {
  7. 7.foreach ($member in $group.Members) {
  8. 8.$memberGroup = Get-ADGroup -Identity $member -ErrorAction SilentlyContinue
  9. 9.if ($memberGroup -and $memberGroup.memberOf -contains $group.DistinguishedName) {
  10. 10.Write-Host "Circular reference: $($group.Name) <-> $($memberGroup.Name)"
  11. 11.}
  12. 12.}
  13. 13.}
  14. 14.}
  15. 15.Find-CircularGroupNesting
  16. 16.`
  17. 17.Check token size for affected users:
  18. 18.```powershell
  19. 19.# Estimate Kerberos token size for a user
  20. 20.function Get-UserTokenSize {
  21. 21.param([string]$Username)
  22. 22.$user = Get-ADUser -Identity $Username -Properties memberOf
  23. 23.$groups = $user.memberOf
  24. 24.$estimatedSize = ($groups.Count * 40) + 1200
  25. 25.Write-Host "User: $Username"
  26. 26.Write-Host "Group count: $($groups.Count)"
  27. 27.Write-Host "Estimated token size: $estimatedSize bytes (max: 49152)"
  28. 28.if ($estimatedSize -gt 48000) {
  29. 29.Write-Warning "Token size approaching Kerberos limit!"
  30. 30.}
  31. 31.}
  32. 32.Get-UserTokenSize -Username "jdoe"
  33. 33.`
  34. 34.Remove the circular reference:
  35. 35.```powershell
  36. 36.# Remove GroupA from GroupB's membership to break the cycle
  37. 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. 1.Use AD Administrative Center to visualize nesting:
  2. 2.```powershell
  3. 3.# Export group membership for analysis
  4. 4.Get-ADGroup -Filter {Name -like "App_*"} -Properties Members, memberOf |
  5. 5.Select-Object Name,
  6. 6.@{N='Members';E={$_.Members -join '; '}},
  7. 7.@{N='MemberOf';E={$_.memberOf -join '; '}} |
  8. 8.Export-Csv -Path "group-nesting.csv" -NoTypeInformation
  9. 9.`
  10. 10.Open the CSV in Excel and use conditional formatting to highlight circular references.
  11. 11.Implement MaxTokenSize registry fix for large groups (temporary workaround):
  12. 12.```powershell
  13. 13.# On the affected server (NOT a long-term solution)
  14. 14.Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters" `
  15. 15.-Name "MaxTokenSize" -Value 65535 -Type DWord

# Reboot required Restart-Computer ```

  1. 1.Prevent future circular references with a validation script:
  2. 2.```powershell
  3. 3.# Run before adding group membership
  4. 4.function Test-GroupNestingSafe {
  5. 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-GroupNestingSafe script
  • Keep group nesting depth to 3 levels or fewer
  • Monitor Kerberos token sizes for users with many group memberships
  • Use AD schema attribute tokenGroups for efficient group resolution
  • Implement change management approval for group nesting modifications
  • Run periodic audits with Find-CircularGroupNesting script