🏢Active DirectoryGPOCompliancePermissionsAttack Paths

Weak ACL GPO, Tier 0 OU, Active Directory: The Pivot That Undoes the Tier Model You Just Built

Your Tier 0 OU blocks inheritance, but the GPOs linked to it are a second, independent ACL boundary that is rarely audited once the tier model ships.

Younes AZABARBy Younes AZABAR10 min read
Weak ACL GPO, Tier 0 OU, Active Directory: The Pivot That Undoes the Tier Model You Just Built

Weak ACL GPO, Tier 0 OU, Active Directory: What This Misconfiguration Actually Is

A weak ACL GPO, Tier 0 OU, Active Directory link is the control most teams forget to check once their tier model has already shipped. Creating a dedicated Tier 0 organizational unit and blocking policy inheritance on it is a well-known step — it is R58 and R59 of ANSSI-PA-099, the French cybersecurity agency's guide on securing Active Directory administration (see our rundown of the ANSSI recommendations for the broader set). R58 requires a dedicated OU gathering the Tier 0 objects — with an explicit carve-out: domain controller computer accounts and the built-in users and groups stay in their default OUs; R59 requires that this OU "restrict the security policies applicable to the Tier 0 organizational unit" by blocking inheritance and making sure any GPO linked or applied to it is dedicated to Tier 0 resources and editable only by Tier 0 administrators.

That second half of R59 — "editable only by Tier 0 administrators" — is the part that quietly falls out of scope once the OU structure is built. Blocking inheritance closes one control plane: which policies flow down onto the OU. It says nothing about a second, independent control plane: who can write to the GPO objects that are already linked there. A GPO is its own Active Directory object with its own access control list. If that ACL grants edit rights to anyone below Tier 0 — a helpdesk group, a departed delegation that was never cleaned up, a security group nested one level deeper than intended — that low-trust principal can rewrite the policy content, and Active Directory will apply their changes to every Tier 0 computer and account the GPO reaches, inheritance block or not.

This is a narrower, more specific failure than the general question of how a tier model gets built in the first place. A team can implement the OU hierarchy from R58 correctly, pass every review of the OU structure itself, and still ship a Tier 0 OU with one weakly-permissioned GPO attached to it — because the GPO's own ACL is a separate object that nobody thought to re-check after the tier model was declared done.

How It Works

A Group Policy Object is really two artifacts kept in sync: the Group Policy Container (GPC), an Active Directory object under CN=Policies,CN=System,DC=<domain> that carries the GPO's own security descriptor, and the Group Policy Template (GPT), the matching folder in the SYSVOL share that holds the actual settings files. The link between a GPO and an OU is a separate, third piece: the gPLink attribute on the OU, which just references the GPO by GUID.

Microsoft's own documentation on Group Policy processing confirms the mechanics behind R59's "block inheritance" requirement: each OU has a GPOptions attribute that can block policies from higher-level containers, but "while blocked inheritance prevents most settings from applying to an OU, it doesn't affect settings applied through GPOs with the enforced option" — enforced is a link property and takes precedence over block inheritance, a container property. That is exactly why R59 also requires checking that no GPO applied with enforced status from a parent OU is editable by anyone outside Tier 0: block inheritance alone does not stop an enforced GPO's permissions problem, only its normal-priority one.

None of this touches the GPC object's own ACL. By default, only Domain Admins, Enterprise Admins, and SYSTEM hold edit rights on a GPO — Microsoft's Get-GPPermission reference shows exactly that default set in its own sample output, and names this permission level GpoEditDeleteModifySecurity. Weak ACLs show up through drift, not through a single bad decision: a GPO gets created by a lower-tier admin via GPMC and is later linked to the Tier 0 OU without anyone re-auditing who still holds edit rights on it, or a helpdesk delegation that was scoped to a specific GPO for a specific task never gets revoked, or a security group intended for Tier 1 gets accidentally granted "Edit settings" during a permissions cleanup.

The Attack Chain

An attacker (or an auditor) enumerates every GPO's ACL for GenericAll, GenericWrite, WriteDacl, or WriteOwner grants held by a principal below Tier 0, then cross-references the result against every GPO's gPLink on a Tier 0 OU — directly, or via an enforced GPO on a parent OU. Get-GPPermission -Guid <GPO GUID> -All surfaces this one GPO at a time — -Guid (or -Name) is mandatory, so the sweep has to iterate rather than run once: any trustee whose Permission comes back as GpoEditDeleteModifySecurity — or a custom ACE the cmdlet can't map to a named level — and isn't a recognized Tier 0 principal is a hit.

Step 2 — Weaponize the policy

SpecterOps' BloodHound documentation on the GenericWrite abuse edge describes the standard technique: open the GPO in the Group Policy Management Editor and add "an evil policy that allows item-level targeting, such as a new immediate scheduled task" — a Group Policy Preferences feature that runs an arbitrary command as NT AUTHORITY\SYSTEM the next time the policy applies. The tools named for this — SharpGPOAbuse on Windows, pyGPOAbuse on Linux — automate writing that scheduled-task XML into the GPO. The same documentation flags an important limit: GenericWrite scoped to "this object only," with no other ACE, is not enough on its own — the GPT settings live in SYSVOL, so the attacker also needs write access to that GPO's SYSVOL folder to actually change what gets deployed. In practice the two access paths are granted together often enough that this is a real attack path, not just a theoretical one — but it is also the detail that separates a true weak-ACL GPO from a false positive.

Step 3 — Wait for the refresh window

No further access is required after the edit. Per Microsoft's documentation above, domain member computers and servers re-check for GPO changes every 90 minutes with a random offset of up to 30 minutes, while domain controllers check every five. SYSVOL content itself replicates between domain controllers on a DFSR schedule as short as 15 minutes within a site. Once the change lands, every Tier 0 computer the GPO reaches — for a GPO linked at the Tier 0 OU, that means the Tier 0 admin workstations, administration accounts and service accounts held there — runs the attacker's task as SYSTEM on its own schedule, no interaction required. Domain controllers are a separate hop: R58 keeps their computer accounts in the default OU=Domain Controllers, so a weak GPO reaches a DC only if it is also linked to that OU or applied to a parent container with enforced status.

Detection

IndicatorEvent IDSourceDescription
GPO object modified5136Security log, DCObjectClass=groupPolicyContainer, with AttributeLDAPDisplayName showing which property changed (e.g. nTSecurityDescriptor, gPCFileSysPath, gPCMachineExtensionNames)
GPO permission grant to unexpected trusteeGet-GPPermission -All sweepAny Permission of GpoEdit or GpoEditDeleteModifySecurity held by a principal outside the recognized Tier 0 admin group
GPO linked to a Tier 0 OUgPLink attribute of the OUCross-reference every linked/enforced GUID against the weak-ACL list from the sweep above

Event ID 5136 ("A directory service object was modified") fires under the Audit Directory Service Changes subcategory whenever an object with an appropriate SACL entry for "Write" auditing is changed — it will not appear at all unless that SACL is configured on the GPO container objects (or inherited from CN=Policies,CN=System) in advance. The event's AttributeLDAPDisplayName field is what lets a SIEM tell a routine policy edit from a security-descriptor change; filtering on ObjectClass=groupPolicyContainer isolates GPO activity from every other directory-service change this event also covers.

# Sweep every GPO for trustees with edit/full-control rights, then
# cross-reference against GPOs linked to a Tier 0 OU
Get-GPO -All | ForEach-Object {
    $gpo = $_   # keep the GPO: inside the nested pipeline $_ is a GPPermission
    Get-GPPermission -Guid $gpo.Id -All |
        Where-Object { $_.Permission -match 'GpoEdit|GpoCustom' } |
        Select-Object @{N='GPO';E={$gpo.DisplayName}}, Trustee, TrusteeType, Permission
}

Remediation

  1. Inventory the exposure. List every GPO linked to the Tier 0 OU, plus any GPO applied with enforced status from a parent OU — per ANSSI-PA-099 R59, both count. (Get-GPInheritance -Target "<Tier0 OU DN>").GpoLinks returns the directly linked set; check parent OUs manually for enforced links.
  2. Review the Delegation tab. For each GPO, open it in GPMC and check the Delegation tab, then click Advanced to see the raw ACL rather than the summarized permission levels — Microsoft's delegation guidance documents this as the supported path to add, remove, or inspect Edit settings, delete, and modify security grants on a GPO.
  3. Remove any trustee outside Tier 0 holding Edit, Edit/Delete/Modify Security, or a Custom permission level. Confirm the corresponding SYSVOL folder for that GPO does not separately grant the same principal write access — the AD ACL and the SYSVOL ACL are two different checks on two different objects.
  4. Re-verify R59's other half. Confirm inheritance is still blocked on the Tier 0 OU, that the Default Domain Policy is linked there at the lowest priority as R59 specifies, and that no enforced GPO from a parent OU still carries a weak ACL.
  5. Re-run the sweep from the Detection section on a schedule, not just once — GPO permissions drift the same way group memberships do, through one-off delegations nobody remembers to revoke. This check belongs in the same rotation as a broader Active Directory security audit, not as a one-time cleanup.

How EtcSec Detects This

EtcSec's compliance catalogue tracks this exact failure mode as ANSSI_R59_TIER0_OU_POLICIES: it enumerates every enabled GPO link, flags the ones pointing to a GPO whose own ACL grants write access to a non-admin principal, and reports a finding for each link that lands on a Tier 0 OU. It's paired with GPO_DANGEROUS_PERMISSIONS for the general case of weak GPO ACLs anywhere in the domain, PATH_GPO_TO_DA for the attack-path view of the same exposure, and ANSSI_R15_TIER_MODEL_VIOLATION for the broader question of whether the tier model itself is intact.

Explore the identity security pages that support this topic