If an attacker can edit a GPO, they can often achieve silent, scalable code execution across fleets. This guide shows how to detect that abuse (and how to reduce your blast radius when it happens).
Why GPO-permission abuse is high impact
Group Policy is a centralized control plane. That’s the feature—and the risk. A single rights mistake (or an over-delegated group) can let someone:
- Push startup/logon scripts, scheduled tasks, services, and registry changes across many hosts.
- Grant themselves local admin everywhere via Group Policy Preferences or Restricted Groups.
- Disable security tooling, weaken firewall rules, or turn off logging.
- Target only high-value systems using security filtering or WMI filters.
If you want a refresher on how GPOs work end-to-end, start with Active Directory Group Policy and Managing GPOs with Group Policy Management Console (GPMC).
First-principles model: what a GPO really is
Detection becomes simpler when you model the “attack surface” correctly. A GPO is two things:
1) GPC (Group Policy Container) in Active Directory
Lives under CN=Policies,CN=System,DC=.... Stores metadata (version, extensions, security descriptor).
Changing links and permissions is usually an AD object change.
2) GPT (Group Policy Template) in SYSVOL
Lives under \\<domain>\SYSVOL\<domain>\Policies\{GUID}. Stores files like
gpt.ini, Registry.pol, scripts, and preferences XML.
Abuse happens when an attacker can modify either side:
- AD-side: change the GPO ACL, change link targets (gPLink), create new GPOs, change WMI filters/security filtering.
- SYSVOL-side: drop/modify scripts, scheduled tasks, preference items, or policy files.
Delegation is often necessary—but it must be intentional and narrow. See GPO Delegation and How to delegate permissions to create GPOs for the operational basics.
Common abuse paths (what attackers actually do)
1) “I can edit a GPO” → fleet-wide execution
- Add a startup script under
Machine\Scripts\Startup(runs as LocalSystem). - Create a scheduled task via GPP under
Machine\Preferences\ScheduledTasks. - Modify
Registry.polto add persistence (Run keys, services, Winlogon settings).
2) “I can change GPO permissions” → future stealth + guaranteed access
- Grant themselves Edit settings or Edit, delete, modify security on critical GPOs.
- Add a nested group that looks legitimate (e.g., “IT-Workstations-Operators”) and delegate through it.
- Change GPO owner to a service account to blur accountability.
3) “I can link GPOs (or modify gPLink)” → apply malicious policy without touching existing GPOs
- Create a new GPO and link it to the Domain root, DC OU, or server OUs.
- Change link order (higher precedence) or set the link as “Enforced”.
- Use filtering to target only admin workstations or a specific server tier.
Filtering is a double-edged sword: it’s good for precision, and good for attackers too. Review GPO security filtering and WMI filtering with a detection mindset: “Who can change filters, and would we notice?”
Turn on the right auditing (without drowning)
- AD object changes related to GPOs and GPO links
- SYSVOL file writes under policy GUID folders
1) Audit AD-side changes: Directory Service Changes
Enable Advanced Audit Policy for Directory Service Changes on domain controllers (success at minimum). This is where you can catch:
- GPO object modified (5136)
- GPO object created (5137)
- GPO object deleted (5141)
Then apply SACLs (auditing entries) on:
CN=Policies,CN=System,DC=...(to track GPO container changes)- High-value OUs (to track
gPLinkandgPOptionschanges)
2) Audit SYSVOL writes: Object Access / File System
Turn on file system auditing where SYSVOL is stored on DCs and set auditing on policy folders for write events. This helps detect:
- New or modified scripts (BAT/PS1/VBS) under GPO folders
- GPP XML modifications (ScheduledTasks, Services, LocalUsersAndGroups, Registry, etc.)
gpt.inichanges and suspicious version bumps
Practical tip: focus auditing on critical policy GUID folders (Domain/Domain Controllers/Server tier) instead of blanket auditing every policy folder if volume is a concern.
High-signal detections and SIEM rule ideas
Detection A: Unauthorized GPO ACL changes
Trigger when a GPO’s security descriptor changes (AD event 5136 where the changed attribute is nTSecurityDescriptor)
and the actor is not an approved admin group.
- Where: DC Security log
- Signal: 5136 + attribute:
nTSecurityDescriptoronCN={GUID},CN=Policies,... - Enrich: map GUID → DisplayName via PowerShell
Detection B: New GPO created then linked quickly
Attackers often create a fresh GPO to avoid scrutiny, then link it to a high-value OU.
Correlate: 5137 (new object under Policies) followed by 5136 on an OU’s gPLink.
- Signal: “create → link” within 5–15 minutes
- Higher severity: linked to DC OU / server tiers / admin workstations
Detection C: OU gPLink tampering
Detect changes to gPLink (link addition/removal) and gPOptions (block inheritance).
Alert on unexpected precedence changes or enforced links.
- Signal: 5136 on OU DN with attribute:
gPLinkorgPOptions - Enrich: decode GUIDs in gPLink, check link order changes
Detection D: SYSVOL policy-file writes
Watch for writes to suspicious paths:
...\Policies\{GUID}\Machine\Scripts\Startup,
...\Machine\Preferences\ScheduledTasks,
...\Machine\Preferences\Groups,
Registry.pol, and gpt.ini.
- Signal: 4663 (object access) on DC file system (if enabled)
- Higher severity: script additions + GPO linked to many OUs
- Non-standard admin account changes GPO ACLs and modifies SYSVOL files within minutes.
- New GPO created + linked to DC OU + contains startup script or scheduled task.
- GPO permission change grants “Edit, delete, modify security” to a broad group (Helpdesk/IT-Staff/All-IT).
- Filter changes (security/WMI) that narrow scope to “Admin” systems right before a policy update.
PowerShell checks: baseline, drift, and “who can edit what”
Your fastest detection wins come from answering two questions continuously:
- Who can modify critical GPOs? (permissions)
- What changed? (content drift)
1) List permissions on a critical GPO
# Requires RSAT: GroupPolicy module
Import-Module GroupPolicy
$gpoName = "Default Domain Controllers Policy"
Get-GPPermission -Name $gpoName -All |
Select-Object Trustee, TrusteeType, Permission, Inherited |
Sort-Object Trustee
2) Find “non-standard editors” across many GPOs
Import-Module GroupPolicy
# Customize this allow-list to match your org.
$allowed = @(
"DOMAIN\\Domain Admins",
"DOMAIN\\Enterprise Admins",
"DOMAIN\\Group Policy Creator Owners"
)
Get-GPO -All | ForEach-Object {
$gpo = $_
$perms = Get-GPPermission -Guid $gpo.Id -All |
Where-Object { $_.Permission -match "GpoEdit|GpoEditDeleteModifySecurity" }
foreach ($p in $perms) {
$t = ($p.Trustee.Name -as [string])
if ($t -and ($allowed -notcontains $t)) {
[pscustomobject]@{
GPOName = $gpo.DisplayName
GPOGuid = $gpo.Id
Trustee = $t
Permission = $p.Permission
Inherited = $p.Inherited
}
}
}
} | Sort-Object GPOName, Trustee
3) Create a “known-good” snapshot you can diff later
Import-Module GroupPolicy
$out = "C:\\GPO-Audit\\"
New-Item -ItemType Directory -Force -Path $out | Out-Null
# Export permissions snapshot
$permSnap = Join-Path $out ("gpo-permissions-" + (Get-Date -Format "yyyyMMdd-HHmmss") + ".csv")
$rows = foreach ($gpo in Get-GPO -All) {
foreach ($p in (Get-GPPermission -Guid $gpo.Id -All)) {
[pscustomobject]@{
GPOName = $gpo.DisplayName
GPOGuid = $gpo.Id
Trustee = $p.Trustee.Name
Type = $p.TrusteeType
Permission = $p.Permission
Inherited = $p.Inherited
}
}
}
$rows | Export-Csv -NoTypeInformation -Path $permSnap
$permSnap
Pair this snapshot with regular GPO backups (GPMC) to support clean diffing when something changes.
Investigation workflow: from event → GPO diff → scope of impact
Step 1: Identify the exact GPO and actor
- From DC event logs, extract the DN (often includes
CN={GUID},CN=Policies,CN=System,...). - Record: subject account, source workstation, timestamp, and changed attribute.
Step 2: Map GUID → DisplayName quickly
Import-Module GroupPolicy
$guid = "{PUT-GPO-GUID-HERE}"
(Get-GPO -Guid $guid).DisplayName
Step 3: Determine impact scope (where does it apply?)
- Which OUs is it linked to?
- Is the link enforced? Is inheritance blocked on target OUs?
- Is security filtering or WMI filtering limiting it to a specific set (possibly “admins only”)?
Step 4: Diff the content (what actually changed?)
- Use GPMC backup comparison if you maintain periodic backups.
- Export a report now for evidence preservation:
Import-Module GroupPolicy
$gpoName = "PUT-GPO-NAME-HERE"
Get-GPOReport -Name $gpoName -ReportType Html -Path "C:\\GPO-Audit\\GPOReport.html"
Step 5: Confirm affected machines and timelines
- Find machines in linked OUs and identify which have applied the policy recently.
- On sample endpoints, use
gpresult /hand review applied GPOs and last refresh time. - If you centralize endpoint logs, look for correlated changes: new local admins, new scheduled tasks, service installs, script executions.
Hardening patterns: prevent and contain
1) Reduce who can edit critical GPOs (and make it reviewable)
- Use dedicated groups for GPO editing (per tier), not broad IT groups.
- Eliminate direct user assignments; delegate to groups only.
- Review nested memberships regularly (nested groups are how broad access hides).
2) Separate “create GPO” from “link GPO” from “edit GPO”
- Creation rights: tightly controlled (avoid “everyone in IT can create GPOs”).
- Linking rights: extremely sensitive on high-value OUs.
- Editing rights: scoped to specific policy sets.
3) Require privileged access workstations (PAWs) for GPO management
- GPO changes should originate from hardened admin endpoints only.
- Alert when GPMC activity appears from a non-PAW subnet or non-admin workstation.
4) Version control for GPOs (treat them like code)
- Frequent backups (daily for critical GPOs).
- Documented change windows and approvers.
- Automated diffing for drift detection.
5) Guardrails on SYSVOL
- Monitor writes to policy folders; alert on scripts and scheduled task preferences.
- Ensure only appropriate principals can modify GPO files.
- Harden SMB and ensure DCs are patched (SYSVOL is a high-value target).
Operational checklist
Weekly
- Review “non-standard editors” report across all GPOs.
- Review recent changes to
CN=Policiesand critical OUs. - Spot-check security/WMI filters for unexpected narrowing.
Daily (for critical tiers)
- Back up critical GPOs and retain snapshots.
- Alert on 5136
nTSecurityDescriptorchanges on critical GPO GUIDs. - Alert on SYSVOL writes to scripts, scheduled tasks, groups, and
Registry.pol.


