Organisations rarely have just one domain. Mergers, acquisitions, geographic separation, and administrative boundaries all lead to multiple domains and forests that need to share access. Trusts are the relationships that let a principal in one domain authenticate to resources in another. They are essential plumbing — and they are also the roads an attacker uses to move from a domain they own into one they do not.
What a trust actually is
A trust is an agreement that lets one domain's authentication authority vouch for its users to another domain. When domain A trusts domain B, users from B can be granted access to resources in A. The trust is backed by a shared inter-domain key, and Kerberos uses it to issue referral tickets that carry a user across the boundary.
The dimensions of a trust
| Property | Meaning |
|---|---|
| Direction | One-way (A trusts B, so B's users can access A) or two-way (both). Trust flows opposite to access |
| Transitivity | Transitive trusts extend through the chain — if A trusts B and B trusts C, A effectively trusts C |
| Intra-forest | Trusts between domains in the same forest — automatic, two-way, and transitive |
| External | A trust to a domain in another forest — non-transitive by default |
| Forest trust | A trust between two forest roots; transitive within each forest's domains |
The direction trips people up: trust flows opposite to access. If domain A "trusts" domain B, it is B's users who gain access to A's resources. When you read a trust relationship, ask "whose users can reach whose resources?" rather than following the arrow literally.
The forest is the security boundary
This is the single most important fact about trusts, and it is worth repeating from the fundamentals page. Inside a forest, all domains trust each other automatically, transitively, and two-way, and they share the schema and configuration partitions. That means compromising any domain in a forest generally leads to compromising the whole forest — most directly via the Enterprise Admins group or by abusing the trust key between a child and the forest root.
A separate forest, with only an external or forest trust, is a genuine boundary — but only if it is configured with the protections below. A separate domain in the same forest is not a boundary at all.
SID history and SID filtering
The classic cross-boundary attack turns on two features. When a user moves between domains (say during a migration), their old SID can be preserved in the SID history attribute so they keep their old access. Windows honours SID history when making access decisions.
The abuse: if you can write SID history — or forge a ticket that includes it — you can insert the SID of a privileged group from the target domain (e.g. the target's Domain Admins or Enterprise Admins) into a principal you control. When that principal crosses the trust, the target treats it as a member of that privileged group.
SID filtering is the defence: it strips SIDs from outside the trusted domain out of tickets crossing the boundary, so an injected foreign privileged SID is discarded. Intra-forest trusts do not apply SID filtering by default (they are meant to be a single trust zone), which is again why the forest, not the domain, is the real boundary. External and forest trusts should have it enabled — and when they do not, the cross-forest path opens up.
Cross-boundary attack paths
| Scenario | Technique |
|---|---|
| Child domain → forest root | Forge an inter-realm ticket with the trust key and inject the root's Enterprise Admins SID (intra-forest, no SID filtering) |
| Extract the trust key | DCSync the trust account (<domain>$) to get the inter-domain key |
| Cross external trust with weak filtering | Inject a foreign privileged SID via SID history if filtering is disabled |
| Foreign group membership | Users/groups from a trusted domain that have been granted rights in the target — legitimate but often over-broad |
| Kerberoast across a trust | Request service tickets for SPNs in a trusted domain and crack them locally |
# enumerate trusts
netexec ldap dc01 -u jdoe -p pass -M enum_trusts
# PowerView
Get-DomainTrust -Domain corp.local
# BloodHound maps trusts and cross-domain ACL/group edges visually
# child-to-parent via trust key + SID history (conceptual)
ticketer.py -nthash <trust_key> -domain-sid <child_sid> \
-extra-sid <root_sid>-519 -domain child.corp.local Administrator
Detection and defence
| Control | Effect |
|---|---|
| Enable SID filtering on external/forest trusts | Discards injected foreign SIDs — the core cross-forest defence |
| Enable selective authentication | Requires explicit per-resource grants for cross-trust access rather than blanket authenticated-users access |
| Audit SID history | Legitimate only during migrations; lingering or unexpected SID history is a finding |
| Minimise and review trusts | Remove trusts that are no longer needed; each one is an attack surface |
| Treat the forest as one blast radius | Do not rely on domain separation for isolation; use separate forests for genuinely separate security zones |
The takeaway
Trusts let identity cross domain and forest boundaries, and attackers ride them in the same direction access flows. Within a forest there is effectively no boundary at all — own one domain and the forest is reachable, because intra-forest trusts are automatic, transitive, and unfiltered. Across forests, the boundary holds only when SID filtering and selective authentication are configured; where they are not, SID history injection and trust-key forgery carry privilege across. Map trusts early with BloodHound or PowerView, understand which are intra-forest versus external, and remember that the forest is the unit of compromise. The key-extraction step relies on DCSync, and the ticket forging on ticket attacks.