Swazee mark Product (type slug) Tool (chevron-wrench) Experiment (4-point star) Active (filled diamond) Shipped (hollow diamond) Shelved (diamond + slash) External link (↗) Search (angular magnifier) Filter (funnel) Close / Esc (chunky X) Move down (j) Move up (k) Return / Enter
SWAZEENET
VOL. I · NO. 01 · EST. MCMLXXXVII
BROADSIDE 12 active · 2026·05·14
№ 06 · product · TypeScript / Node 20 · 2025—

dirsim,
an Active Directory you can break safely.

A behavioral simulator of Microsoft Active Directory. Forests, OUs, users, groups, GPOs, trusts, Kerberos-style tickets, replication topology --- exposed via REST/SSE plus a Next.js console.

ad typescript

dirsim is not an LDAP/Kerberos wire-protocol reimplementation. The concepts and enforcement semantics match AD; the transport is HTTP+JSON. Every write goes through a Validate → Authorize → Append DirectoryEvent → Publish → Project pipeline, which is what makes scenario reset, time travel, and replication-delay simulation work. NT hashes are computed for real so external attack tooling can be exercised against exported data, but no real wire crypto goes over the network.

ITech scope

IIArchitecture

Event-sourced mutation pipeline. Every write follows the same five-step path: validate with Zod, authorize against operator RBAC (owner > scenario_author > observer), append a DirectoryEvent to the log, publish on the in-process event bus, and project into the in-memory directory. The event log is the source of truth; the directory is a projection. That separation is what makes scenario reset, time travel, and replication-delay simulation work — resetting a scenario means replaying from a starting event index, and a "lossy replication link" is a per-replica filter that holds events back for a configurable lag.

Kerberos is simulated, not real. Tickets are signed JWTs whose claim shape mirrors a real PAC: SIDs, group membership, four delegation modes (none, unconstrained, constrained, RBCD), and the same flag bits a Kerberoast attempt would inspect. The signed-JWT tickets are sufficient to exercise PowerView, BloodHound, and Rubeus-style tooling against the export, but they do not implement the actual ASN.1 KRB-CRED structure. NT hashes are real because the value of an attack-tooling exercise is in the credential math, not the wire format.

The Resultant Set of Policy engine in @dirsim/policy implements LSDOU ordering, Block Inheritance, Enforced links, and loopback processing, which is enough to reproduce most of the GPO ordering bugs that show up in real environments. Replication topology is a directed graph of replicas with per-edge latency; an event published in forest A appears in a peer in forest B at the configured delay, which is what lets the simulator reproduce the "AD looked fine on DC1 and broken on DC2" class of incident.

IIIWorkspace map

The monorepo is npm workspaces (Node 20+). Packages are scoped @dirsim/*; the apps depend on packages, never the other way around, and the dependency graph is a DAG enforced by Turborepo’s task pipeline.

IVWhere the line is drawn

dirsim is a behavioral simulator, not an emulator. It implements the state machine a real Active Directory goes through — with realistic timings, replication delays, GPO precedence, and Kerberos failure modes — but it does not speak the LDAP wire protocol or the SMB stack. That choice keeps the surface comprehensible and the model testable. It also means dirsim cannot stand in for a real domain controller for any tool that talks raw LDAP at a TCP socket; the read-only LDAP bridge is provided as a partial accommodation, and its limits are called out at the API boundary so an integrator does not learn them from a confusing outage.

Fig. I.
01client 02REST 03sim core 04event bus 05SSE 06Next.js console
as of 2026-04-26
Fig. II.
packages 7272 58% apps 4630 37% seeds
apps/ + packages/ + seeds/ · as of 2026-04-26

VSurface

The surface is an 18-endpoint REST API plus an SSE event channel and a Next.js 14 console that consumes both. Operators describe a topology — forests, trusts, OUs, GPOs, GPO links, group memberships, well-known SIDs, replication links — in plain JSON; the simulator boots that JSON into a running model with replication latency, GPO precedence (LSDOU + Block Inheritance + Enforced + loopback), and Kerberos state machines that you can poke and observe in real time over the SSE channel. The use case is “what does this misconfiguration actually do” experimentation without standing up a real lab forest, plus exercising attack tooling like BloodHound and Rubeus against a known-good fixture.

VIConstraints

This is a behavioral simulator, not an emulator. It does not implement the LDAP wire protocol or the SMB stack; it implements the state machine that a real AD goes through, with realistic timings, replication delays, GPO ordering puzzles, and Kerberos failure modes. That choice keeps the surface comprehensible and the model testable in plain TypeScript, but it means dirsim cannot stand in for a real domain controller for any tool that talks raw LDAP at a TCP socket. The read-only LDAP bridge in @dirsim/ldap-bridge is provided as a partial accommodation for tools that absolutely insist on speaking LDAP, but its limits (read-only, no schema modification, no replication topology surfaced via LDAP) are called out at the API boundary so an integrator does not learn them from a confusing outage.

:/ ESC