Find the routes to Domain Admin that your monitoring would not catch —
without your Active Directory data ever leaving the machine.
Quickstart · Collecting · Data handling · Verify the binary
Active Directory accumulates permissions for twenty years and nobody removes any of them. Somewhere in that sprawl is a chain from an ordinary account to complete control of the domain. Harbinger finds those chains, ranks them by whether your monitoring would actually notice someone using them, and names the one change that closes the most of them.
It reads a file. It never touches your directory, never uses credentials, and in its default mode opens no network connections at all.
$ harbinger gen-testdata --format=adexplorer sample.dat
$ harbinger analyze sample.dat
HARBINGER — attack-path exposure analysis
──────────────────────────────────────────────────────
Loaded 8 objects across 12 edge(s)
Crown objective: DOMAIN ADMINS@CORP.LOCAL
⚠ 5 routes to full control of DOMAIN ADMINS would
probably not be noticed while it was being used.
Do this first
Remove SVC-BACKUP@CORP.LOCAL's directory replication
rights (Replicating Directory Changes and Replicating
Directory Changes All) on CORP.LOCAL. On its own this
closes 2 of the ranked routes.
What this run could NOT see
- Sessions were not collected — paths that start from
a logged-on user's credential are invisible here.
Top 5 paths (ranked by reachable-and-undetected risk)
#1 risk 0.749 | 1 hop | 77% evasion — BLIND SPOT
SVC-BACKUP@CORP.LOCAL ─[DCSync]─ CORP.LOCAL
#2 risk 0.480 | 2 hops | 61% evasion — BLIND SPOT ★crown
HELPDESK@CORP.LOCAL ─[GenericAll]─ TIER1ADMINS@CORP.LOCAL
⇢[MemberOf]⇢ DOMAIN ADMINS@CORP.LOCAL
Those two commands work on your machine right now, against a synthetic directory the tool writes itself — no client data, no network. The output above is that run, trimmed for length.
From source — the build is reproducible; the same tag produces byte-identical output on any machine.
go install github.com/harbingerlabs/harbinger-cli/cmd/harbinger@latestOr clone and build:
git clone https://github.com/harbingerlabs/harbinger-cli
cd harbinger-cli
make build # -> bin/harbingerSigned binaries are not published yet. Releases will carry Authenticode-signed Windows executables with published
SHA256SUMS; the code-signing certificate is in progress. Until then, build from source — an unsigned security tool is worse than no download at all, so we are not shipping one. See docs/SIGNING.md.
Then confirm it works, before it ever sees client data:
harbinger checkRuns the whole pipeline against a synthetic directory and asserts the privacy invariant end to end. About a second. No file, no network.
Most Windows admins have never run SharpHound, and running it will very likely trip their EDR — attackers use the same tool, so every endpoint product detects it. On a client network that is not a false positive; it is an incident.
Harbinger reads Sysinternals AD Explorer snapshots natively. AD Explorer is signed by Microsoft, already trusted in a Windows shop, and taking a snapshot looks like what it is: an administrator reading LDAP.
File > Create Snapshot → harbinger analyze snapshot.dat
Already have a BloodHound export? That works too — a .zip, a folder of
.json, or a single .json, in either the CE or the older Legacy
schema. The format is detected from the file's contents, so a renamed file
still works.
→ docs/COLLECTING.md — the full walkthrough, including
what a snapshot can and cannot see. harbinger help collecting prints the same
thing offline, from inside the binary.
There is no upload path in the default mode. Not disabled by default — the tool opens no network connections at all. Disconnect the machine and every command behaves identically.
- Reads one local file, read-only.
- Never contacts Active Directory. Never uses credentials. It has no directory client and no credential store.
- No telemetry. No licence check. No update beacon.
- Zero third-party dependencies — stdlib Go only, so the code you have to read to verify that claim is small and self-contained.
Verify it rather than believe it:
harbinger check # self-test + privacy assertion
harbinger analyze <export> --show-payload # what hybrid mode WOULD send
harbinger analyze <export> --offline # run it behind a packet capture→ docs/DATA_HANDLING.md — the one-page statement.
A reviewer should start at internal/features/features.go: if a value is not
put into a ScoreRequest there, it cannot leave the machine.
A collection gap is never reported as safety. Every report states what it could not see. "No path found" because sessions were not collected says exactly that, rather than implying you are clean.
One document, two readers. The plain-English layer comes first, so the person
who decides whether the work gets scheduled can read it without knowing what
GenericAll means. The ranked paths below stay precise enough for the engineer
making the change.
Routes, not rows. Every member of a group holding a permission can walk the same route with the same fix. That is one finding and a count, not fifteen findings.
Ranked by whether you would notice. A route that is reachable and quiet outranks a shorter one that would light up your SIEM.
harbinger analyze export.dat --report client.htmlwrites a self-contained HTML report you can send to a client — no external requests, no fonts, no scripts — with a real print stylesheet, because these get turned into PDFs.
harbinger diff before.dat after.datReports both directions: routes that opened, and routes that closed — the evidence a fix actually landed. Changes are grouped by cause, with configuration changes ranked above session churn, so a newly granted DCSync is never buried under "an admin logged into a different workstation".
Comparing two different directories is detected and called out rather than silently producing nonsense.
Normal for an MSP, and handled. If an export spans more than one directory, Harbinger lists every one it found and tells you which it ranked against:
harbinger analyze forest.dat --domain acme.localA folder holding two clients' snapshots is refused rather than resolved by guessing — picking one silently is how a report reaches the wrong customer.
harbinger analyze <export> [flags] ranked routes + the top fix
harbinger diff <t0> <t1> what opened, what closed
harbinger check self-test; no file, no network
harbinger gen-testdata [dir|file] write a sample export to try
harbinger help [topic] the manual, offline, in the binary
harbinger version client + feature schema versionThe three documents you need before a first run — how to collect, what leaves
the machine, how to verify the binary — are carried inside the executable:
harbinger help collecting, help privacy, help verify. No checkout and no
browser needed on the machine you are running from.
| Flag | What it does |
|---|---|
--report out.html |
self-contained report (.html or .md) you can send to a client |
--json |
structured output for a PSA/RMM — see below |
--domain <name> |
restrict to one directory when the export holds several |
--top N |
routes to show (default 10) |
--hvt a,b |
designate extra High-Value Targets by SID or name |
--max-starts N |
bound the search on a very large directory |
--show-payload |
print exactly what hybrid mode would transmit |
--offline |
force fully-local scoring (this is the default) |
--no-color |
disable ANSI; NO_COLOR=1 also honoured |
0 success · 1 runtime error (unreadable export, scoring failure) · 2 usage error.
--json emits a versioned envelope so a script can assert on the shape before
trusting it:
{
"schema": "harbinger.analysis/1",
"client": "distilled-1.0.0",
"result": {
"crown_name": "DOMAIN ADMINS@CORP.LOCAL",
"paths": [
{
"rank": 1, "risk": 0.749, "hops": 1, "evasion": 0.77,
"blind_spot": true, "start_count": 3,
"steps": [
{"from_name": "SVC-BACKUP@CORP.LOCAL",
"to_name": "CORP.LOCAL", "edge": "DCSync"}
]
}
],
"top_fix": {
"from_name": "…", "to_name": "…",
"edge": "DCSync", "paths_killed": 2
}
}
}Check schema and fail loudly if it is not the version you built against.
harbinger diff --json uses harbinger.diff/1. Within a major version, fields
may be added, never removed or renamed.
CGO_ENABLED=0 go build -trimpath -buildvcs=false \
-ldflags "-s -w" -o harbinger ./cmd/harbinger
go test ./...-buildvcs=false is not optional if you intend to compare hashes: without it Go
stamps the commit — and whether your working tree was clean — into the binary,
and no two builds agree. CI builds twice, once from a deliberately dirty tree,
and fails if the hashes differ. → docs/VERIFY.md
The tests a reviewer should care about, by name:
| Test | What it prevents |
|---|---|
TestNoIdentityLeak |
any identifier reaching the outbound payload |
TestLegacyAndCEProduceIdenticalGraphs |
old and new BloodHound schemas disagreeing |
TestCorruptionNeverPanics |
a bit-flip anywhere in a snapshot crashing the parser |
TestFolderWithTwoSnapshotsIsRefused |
one client's report being built from another's export |
TestExistingAdminIsNotAStartingPoint |
"an admin is an admin" ranking above real findings |
TestEveryHelpTopicHasEmbeddedContent |
the offline manual silently not shipping |
Worth reading before you rely on it.
- Scores are structural priors, not guarantees. "Unlikely to be detected" assumes common native and endpoint telemetry, not your specific tuned EDR.
- The offline model is a distilled approximation of the calibrated hosted one. Every report says which scorer produced it.
- An LDAP-only snapshot cannot see sessions or local group membership, so host-to-host lateral movement is invisible in that mode. The report says so on its face rather than reporting a clean result.
- No MSP has run this in production yet. It is early. If it is wrong about your directory, we want to hear about it.
| QUICKSTART.md | A result in under ten minutes |
| COLLECTING.md | How to get the data, including the EDR warning |
| DATA_HANDLING.md | What it reads, what it never does, what leaves (nothing) |
| VERIFY.md | Signature, checksums, reproducible build |
| ADEXPLORER.md | Snapshot support: what is extracted, what is not |
| SIGNING.md | Code-signing setup and release process |
| PILOT.md | Design-partner pilot: shape, duration, what we ask |
| MUTUAL_NDA.md | Mutual NDA template, ready to send |
| FEEDBACK.md | Pre-registered measurement instrument |
A wrong answer about a customer's directory is the failure that matters most, so those reports are welcome and get priority. Open an issue — or for anything that looks like a vulnerability in the client or the signed binaries, email security@harbingerlabs.ai rather than filing publicly.
If a verification step in our own documentation does not check out, that is a bug in the software or the document, and we want to know either way.
MIT — see LICENSE.
Built by Harbinger Labs.
