Skip to content
10 · Trusts & Forest DesignPart 2 of 4Intermediate

SID filtering and selective authentication, step by step

Configure and verify SID filtering, quarantine and selective authentication on AD trusts with netdom and PowerShell, including trustAttributes and events.

Florian Amette7 min read

A trust extends your security boundary to whatever is on the other side. If the trusted domain is compromised, two things decide how far the attacker gets: which SIDs your domain controllers accept in the authorization data coming across the trust, and which of your computers accept authentication from trusted principals at all. SID filtering answers the first question and selective authentication answers the second. Both are simple switches, and both are routinely left in the wrong position after a migration or a hurried partner integration.

The trusts and forest boundaries pillar explains why the forest is the boundary. This guide is the operational follow-up: how to read the real state of each trust from trustAttributes, how SID filtering behaves on external versus forest trusts, how to roll out selective authentication without breaking cross-forest access, and how to verify it with events.

Measure: read the trust flags, not the GUI

The trust properties dialog hides several settings. The authoritative source is the trustAttributes bitmask on the trustedDomain object in CN=System.

FlagValueMeaning
NON_TRANSITIVE0x1Trust is not transitive
QUARANTINED_DOMAIN0x4SID filtering (quarantine) on an external trust
FOREST_TRANSITIVE0x8Forest trust
CROSS_ORGANIZATION0x10Selective authentication enabled
WITHIN_FOREST0x20Parent-child or tree-root trust
TREAT_AS_EXTERNAL0x40Forest trust treated as external; SID history allowed
CROSS_ORGANIZATION_NO_TGT_DELEGATION0x200TGT delegation across the trust blocked
PIM_TRUST0x400PAM trust used with shadow principals
CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION0x800TGT delegation across the trust explicitly allowed
PowerShell
Get-ADObject -SearchBase "CN=System,$((Get-ADDomain).DistinguishedName)" `
    -LDAPFilter "(objectClass=trustedDomain)" -Properties trustAttributes, trustDirection, trustType |
  Select-Object Name, trustDirection, trustType,
    @{n='Attr';e={'0x{0:X}' -f $_.trustAttributes}},
    @{n='Forest';e={[bool]($_.trustAttributes -band 0x8)}},
    @{n='Quarantined';e={[bool]($_.trustAttributes -band 0x4)}},
    @{n='SelectiveAuth';e={[bool]($_.trustAttributes -band 0x10)}},
    @{n='SIDHistoryAllowed';e={[bool]($_.trustAttributes -band 0x40)}},
    @{n='TGTDelegationEnabled';e={[bool]($_.trustAttributes -band 0x800)}}

trustDirection 1 is inbound (they trust you), 2 is outbound (you trust them, their users can reach you), 3 is bidirectional. Hardening applies on the side that trusts: the controls below protect the trusting domain from principals in the trusted one. Run the query in every domain that has trusts.

How SID filtering actually behaves

Filtering happens on the trusting side's domain controllers when they process authorization data (the PAC) arriving across the trust.

  • External trusts with quarantine: only SIDs from the trusted domain itself are kept. SID history from any other domain is dropped.
  • Forest trusts (default): SIDs belonging to any domain in the trusted forest are accepted; SIDs claiming to belong to your forest or a third forest are dropped. That means SID history pointing at your own groups is filtered, which is exactly what defeats SID history injection.
  • Forest trusts with /enablesidhistory:yes (TREAT_AS_EXTERNAL): SID history from outside the trusted forest is accepted, except SIDs with RID below 1000. Built-in groups such as Domain Admins and Enterprise Admins are protected, but custom admin groups, Exchange groups and delegated helpdesk groups all have RIDs above 1000 and can be injected.
  • Intra-forest trusts: no filtering. Parent-child trusts are inside the boundary; quarantining them is unsupported and breaks forest operations.

When a DC drops SIDs it logs event 4675, "SIDs were filtered", which gives you a direct signal of either migration fallout or an attempted injection. Legitimate cross-forest access is described in more depth in the SID filtering glossary entry.

Audit: who depends on what

Before tightening, find out what crosses each trust.

  1. Group memberships: foreign security principals in CN=ForeignSecurityPrincipals represent trusted-domain users and groups placed in your groups. Resolve and review them.
  2. Logons: event 4624 on servers with a TargetDomainName from the trusted domain, and 4769 on your DCs for referral tickets, show which machines partner principals actually use.
  3. SID history reliance: any account in the trusted domain whose sIDHistory contains your domain's SIDs, which only works while SID history is allowed. That work belongs in SID history cleanup.
PowerShell
Get-ADObject -SearchBase "CN=ForeignSecurityPrincipals,$((Get-ADDomain).DistinguishedName)" -Filter * -Properties memberOf |
  ForEach-Object {
    $name = try { ([Security.Principal.SecurityIdentifier]$_.Name).Translate([Security.Principal.NTAccount]).Value } catch { 'unresolved' }
    [pscustomobject]@{ SID = $_.Name; Account = $name; MemberOf = ($_.memberOf -join '; ') }
  }

Unresolvable FSPs usually point at deleted partner objects or decommissioned trusts and can be removed from groups.

Enforce: SID filtering

Run netdom on a DC of the trusting domain, as a Domain Admin of that domain. For external trusts:

PowerShell
netdom trust corp.example.com /domain:partner.example.net /quarantine
netdom trust corp.example.com /domain:partner.example.net /quarantine:yes

The first form reports the current state; the second enables quarantine. For forest trusts, restore the default filtering after a migration:

PowerShell
netdom trust corp.example.com /domain:partner.example.net /enablesidhistory
netdom trust corp.example.com /domain:partner.example.net /enablesidhistory:no

While you are in netdom, check TGT delegation. Since the July 2019 updates, unconstrained delegation across forest trusts is blocked by default, and the 0x800 flag in the measurement query shows whether someone re-enabled it. Microsoft's guidance for this switch names the trusted forest first; confirm the argument order with netdom trust /? on your DC:

PowerShell
netdom trust <TrustedForestName> /domain:<TrustingForestName> /EnableTGTDelegation:No

Allowing TGT delegation would let a server with unconstrained delegation in one forest capture TGTs from the other.

Enforce: selective authentication

Selective authentication (CROSS_ORGANIZATION) changes the default for trusted principals from "authenticated users can reach any computer" to "no computer unless explicitly allowed". Roll it out in this order.

1. Create resource-side allow groups

Create a domain local group per resource set in the trusting domain, for example SA-Partner-FileServers, and add the partner's global groups to it. Keeping access in groups you own keeps the ACLs readable.

2. Grant Allowed to Authenticate on each target computer

The right is the extended right Allowed to Authenticate (68b1d179-0d15-4d4f-ab71-46152e79a7bc) on computer objects. Grant it with PowerShell:

PowerShell
$group   = Get-ADGroup "SA-Partner-FileServers"
$sid     = [Security.Principal.SecurityIdentifier]$group.SID
$guid    = [Guid]"68b1d179-0d15-4d4f-ab71-46152e79a7bc"
$targets = "FS01","FS02"

foreach ($t in $targets) {
    $dn  = (Get-ADComputer $t).DistinguishedName
    $acl = Get-Acl "AD:$dn"
    $ace = New-Object DirectoryServices.ActiveDirectoryAccessRule($sid, "ExtendedRight", "Allow", $guid)
    $acl.AddAccessRule($ace)
    Set-Acl "AD:$dn" $acl
}

You generally do not need grants on your domain controllers for partner users to reach member servers. Grant the right on a DC only if partner principals must use a resource hosted on that DC, and never broadly on the Domain Controllers OU.

3. Flip the switch

PowerShell
netdom trust corp.example.com /domain:partner.example.net /SelectiveAuth:yes

The change takes effect as it replicates. Keep /SelectiveAuth:no ready as the rollback, and run the change in a window where the partner can test.

Plan the rollout with the partner

Trust changes affect people you do not manage, so treat them as a joint change rather than a local setting.

  • Share the evidence first. Send the partner the list of foreign security principals and the servers their users actually authenticate to, taken from the 4624 data above. They will often spot stale accounts and unused access you can drop instead of granting.
  • Reduce direction before adding controls. If only their users need your resources, the trust should be one-way outgoing from your domain; a bidirectional trust doubles the surface for no benefit. Recreate the trust in the needed direction rather than hardening a side nobody uses.
  • Prefer forest trusts to external trusts between forests you control, because forest trusts use Kerberos by default, support name suffix routing restrictions and filter SIDs forest-aware. External trusts fall back to NTLM more often, which interacts with any plan to restrict NTLM.
  • Restrict name suffix routing on forest trusts so the partner cannot route authentication for suffixes you did not intend to accept.
  • Agree on a review cycle. Trusts outlive the projects that created them. Put an owner and a review date on every trust, and remove it with netdom trust /remove when the business need ends.

Verify

PowerShell
# Re-run the trustAttributes query above, then cross-check with Get-ADTrust
Get-ADTrust -Filter * | Select-Object Name, Direction, ForestTransitive, SIDFilteringQuarantined, SIDFilteringForestAware, SelectiveAuthentication

# Who is allowed to authenticate to a given server
(Get-Acl "AD:$((Get-ADComputer FS01).DistinguishedName)").Access |
  Where-Object { $_.ObjectType -eq '68b1d179-0d15-4d4f-ab71-46152e79a7bc' } |
  Select-Object IdentityReference, AccessControlType

SIDFilteringForestAware set to True on a forest trust means SID history is allowed, the state you want to reverse. Then test from the partner side: an allowed user reaches FS01; the same user reaching another server should fail with event 4625 status 0xC0000413 on that server. Forward 4675 and 4625 with that status to your SIEM using the collection design in Windows Event Forwarding.

What it breaks

  • Anything relying on implicit access across an open trust: file shares, SQL logins, web apps using Kerberos, and print servers fail for partner users until each target computer has an Allowed to Authenticate grant.
  • Interactive logons by partner users to workstations or RDS hosts in your domain need a grant on every such machine; if that list is long, the trust design itself deserves a review.
  • In-flight migrations break when SID history filtering returns, since migrated users lose access granted through old SIDs.
  • Cross-forest unconstrained delegation scenarios stop working when TGT delegation is disabled; move them to constrained delegation or RBCD.
  • Third-party identity tools that enumerate or authenticate across the trust from arbitrary servers need their own grants.

Related reading: the Trusts & Forest Design topic, the SID history glossary entry, and constrained delegation and RBCD done safely for replacing cross-forest unconstrained delegation.

Frequently asked questions

Is SID filtering enabled by default on forest trusts?

Yes. A forest trust filters SIDs that do not belong to the trusted forest, and external trusts created on modern Windows Server versions are quarantined by default. The problem is drift: migrations often set /enablesidhistory:yes or /quarantine:no and nobody reverts it. Always check the trustAttributes value on each trust rather than assuming the default still applies.

Does enabling SID history on a forest trust allow Enterprise Admins SIDs through?

No. Even with SID history enabled on a forest trust, SIDs with a relative identifier below 1000, which covers built-in groups such as Domain Admins and Enterprise Admins, are still filtered. However, any group with a RID of 1000 or higher is accepted, including custom admin groups or application groups with powerful delegated rights, which is why the setting must be temporary.

What happens to a user blocked by selective authentication?

The authentication fails at the target resource. On the server, event 4625 records the failure with status 0xC0000413, meaning the authentication firewall rejected the request because the user's account is not allowed to authenticate to that machine. The fix is granting the Allowed to Authenticate right on that specific computer object to a group containing the user, not disabling selective authentication.

SID filtering and selective authentication, step by step

Related guides

Trusts & Forest Design

Hardening AD trusts and forest boundaries

Why the forest — not the domain — is the AD security boundary, and how to lock down trusts with SID filtering, quarantine, and selective authentication.

Intermediate
Trusts & Forest Design

Cleaning up SIDHistory after AD migrations

Find, assess and safely remove sIDHistory left over from domain migrations: dangerous SIDs, ACL re-permissioning, staged removal, rollback limits and detection.

Intermediate