ADGPO-006: GPOs with Broken Links
- Platform
- Active Directory
- Category
- AD Group Policy
- Severity
- Medium
- Zero Trust pillar
- Governance (weight 1)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
Guerrilla parses the gPLink attribute on the domain root, every Active Directory site (under CN=Sites,CN=Configuration), and every organizational unit (objectClass=organizationalUnit) in the domain. The gPLink value is a concatenated string of bracketed pairs in the form [LDAP://cn={GUID},cn=policies,cn=system,DC=...;flag] where flag is 0 (link enabled, not enforced), 1 (link disabled), 2 (link enabled and enforced), or 3 (link disabled and enforced). For each parsed GUID the check confirms three conditions: the corresponding Group Policy Container object exists under CN=Policies,CN=System,DC=... and is readable to the auditor; the Group Policy Template folder \\<domain>\SYSVOL\<domain>\Policies\{GUID} exists and is readable; and both halves contain a matching versionNumber so they have not drifted via partial replication. Any link where the GPC is missing, the GPT folder is missing, or the GPC is unreadable due to ACL denial is reported as a broken link, along with the container holding the link and the link flag (enforced links are surfaced first because their absence has the largest configuration impact).
Why it matters
Broken GPO links are a silent control failure. The link still appears in GPMC, in the gpresult /h HTML report, and in dsa.msc when an admin inspects the OU, but the policy never reaches the endpoint. Three concrete risks follow. First, security baselines disappear without any operator-visible signal: if the OU linked GPO that enforced PowerShell ScriptBlock logging or audit subcategory coverage is the broken one, telemetry quietly stops at every machine in scope and the next compromise is invisible. Second, the condition is a known persistence and defense-evasion primitive: an attacker with DS-Replication or Modify-Owner on an OU can break a security GPO link (delete the GPC while leaving the gPLink string referencing it, or strip the SYSVOL folder) and the policy effectively turns off without the link ever appearing modified in the change log. Third, the failure mode masks SYSVOL replication health problems, FRS to DFSR migration artifacts, and orphaned policies left behind by GPMC backup or restore operations, all of which are precursors to broader Group Policy integrity issues such as ADGPO-005 (unlinked GPOs) and ADGPO-004 (SYSVOL ACL drift). Microsoft documents the gpsvc client behavior in event 1058 and 1030: the engine emits these events on every refresh interval when it cannot read the GPT, but most environments suppress or never collect them, so the failures persist for years.
Attack path
An attacker with delegated rights to an OU (Modify gPLink, write to the OU object, or owner) can disable a security GPO without triggering the alarms that fire when a GPO is unlinked or deleted in the usual way. Step one: identify the security GPO that carries the control the attacker wants to defeat, for example a GPO that enforces Windows Defender real-time protection, blocks LSASS read, or pushes audit policy. BloodHound, PowerView (Get-NetGPO, Get-ObjectAcl), or AD security assessment tooling surface the GPC GUID and the OUs it links to. Step two: instead of unlinking, the attacker rewrites the GPT folder under SYSVOL to remove the Machine or User subkey, deletes the GPC object via an ADSI write (which leaves the gPLink string intact), or stages a divergence by removing the GPC on one DC right before a planned replication outage so the GUID effectively vanishes from a subset of the forest. Group Policy clients in scope hit event 1030 or 1058 on next refresh, skip the missing policy, and apply whatever local policy the attacker has prepared instead. Step three: lateral movement and credential theft tooling now run unblocked on the targeted OU. Because gpresult /h still lists the GPO as linked and only the gpsvc Operational log carries the failure, defenders looking at the GPMC tree see a healthy configuration. Sean Metcalf and SpecterOps have written about GPO abuse for persistence using SharpGPOAbuse and the equivalent SeEnableDelegationPrivilege patterns; broken-link engineering is the quieter cousin of those techniques.
How Guerrilla assesses it
Guerrilla performs an LDAP search with filter (|(objectClass=organizationalUnit)(objectClass=domainDNS)(objectClass=site)) and requests the gPLink and gPOptions attributes. It tokenises gPLink on the closing bracket, extracts each GUID, and issues a direct LDAP bind to cn={GUID},cn=policies,cn=system,DC=... to confirm the GPC exists. For every GPC that resolves, it then performs a UNC stat against \\<dnsRoot>\SYSVOL\<dnsRoot>\Policies\{GUID} and reads GPT.INI to compare the versionNumber against the GPC versionNumber attribute. Three failure classes are emitted: BrokenLink_GPCMissing (GUID in gPLink does not resolve in AD), BrokenLink_GPTMissing (GPC exists but the SYSVOL folder is absent or unreadable), and BrokenLink_VersionMismatch (GPC and GPT versionNumber differ by more than one, which indicates stalled replication rather than a transient refresh in flight). The check also reads the gpsvc Operational event log (Microsoft-Windows-GroupPolicy/Operational, event IDs 1058, 1030, 7016, 7017) from any reachable endpoint in scope to corroborate that clients are observing the same failure that the LDAP and SYSVOL inspection predicts.
Recommended value
No broken GPO links; all gPLink references resolve to valid GPOs with intact SYSVOL data
Remediation
Parse gPLink attributes on all OUs, sites, and the domain root to extract referenced GPO GUIDs. Verify each GUID exists in the GPC (AD) and GPT (SYSVOL) containers. Remove broken links using Set-GPLink or by directly editing the gPLink attribute. Investigate the root cause of any missing GPO data.
Fixture-proven verdicts
Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.
| Scenario | Expected verdict |
|---|---|
| clean | PASS |
| known-bad | WARN |
| throttled | Not Assessed |
Framework mappings
- NIST SP 800-53
- CM-3, CM-6
- MITRE ATT&CK
- T1484.001