Active Directory security audit tool -- extract quick wins, attack paths, and misconfigurations from BloodHound CE
Runoff connects to BloodHound Community Edition's Neo4j database over Bolt and runs 183 Cypher queries across 15 categories to surface AD attack paths, misconfigurations, and privilege escalation opportunities. Results come with severity ratings, exploitation commands, and multi-format reporting.
Authorization Required: Designed exclusively for authorized security testing with explicit written permission.
- Python 3.9+
- Neo4j with BloodHound CE data loaded (default Bolt port 7687)
- pip or pipx
# pipx (recommended -- isolated environment)
pipx install git+https://github.com/Real-Fruit-Snacks/Runoff.git
# Or from a local clone
git clone https://github.com/Real-Fruit-Snacks/Runoff.git
cd Runoff && pip install -e .# Run all 183 queries against the local BloodHound database
runoff -p 'bloodhoundcommunityedition' run all
# Quick wins -- high-impact findings only
runoff -p 'pass' quickwins
# Run specific categories with abuse commands
runoff -p 'pass' --abuse run acl adcs delegation
# Filter by severity
runoff -p 'pass' -s critical,high run all
# Investigate a specific node -- properties, edges, memberships, paths
runoff -p 'pass' investigate USER@CORP.LOCAL
# JSON output piped to jq
runoff -p 'pass' -o json run all | jq '.[] | select(.count > 0)'Runoff queries the Neo4j database that BloodHound CE populates from SharpHound/AzureHound collection data. It does not touch Active Directory directly -- it only reads what's already in the graph.
SharpHound/AzureHound --> BloodHound CE --> Neo4j (Bolt:7687) --> Runoff
(collection) (ingestion) (graph database) (analysis)
- Connect to Neo4j over the Bolt protocol (default
bolt://127.0.0.1:7687) - Execute Cypher queries that traverse the BloodHound graph looking for attack paths
- Render results as tables, JSON, CSV, HTML, or Markdown with severity ratings
Queries span 15 categories, each registered via @register_query decorator. Run by category, individually, or filter by severity and tags:
# Run specific categories
runoff -p 'pass' run acl adcs delegation privesc
# Filter by severity
runoff -p 'pass' -s critical,high run all
# Filter by tags (e.g. quick-win, stealthy, requires-creds)
runoff -p 'pass' run all -t quick-win
# Run a single query by name
runoff -p 'pass' query "Kerberoastable Users"
# List all available queries
runoff -p 'pass' query -lRun categories: acl, adcs, privesc, hygiene, lateral, delegation, basic, groups, owned, azure, paths, exchange, gpo, misc (or all for everything).
Shortcut commands for the most common checks -- no need to remember query names:
runoff -p 'pass' kerberoastable # Kerberoastable users
runoff -p 'pass' asrep # AS-REP roastable accounts
runoff -p 'pass' unconstrained # Unconstrained delegation
runoff -p 'pass' nolaps # Computers without LAPS
runoff -p 'pass' spns # Service principal names
runoff -p 'pass' quickwins # High-impact quick wins
runoff -p 'pass' stats # Domain statistics overview
runoff -p 'pass' audit # Full security auditProperties, attack edges, group memberships, admin rights, sessions, and paths to Domain Admins in a single command:
# Full node investigation
runoff -p 'pass' investigate USER@CORP.LOCAL
# Wildcard triage mode -- investigate all service accounts
runoff -p 'pass' investigate 'SVC_*@CORP.LOCAL'
# Node details
runoff -p 'pass' info USER@CORP.LOCAL
# Search by pattern
runoff -p 'pass' search 'ADMIN*'Shortest path queries to high-value targets:
# Paths to Domain Admins
runoff -p 'pass' path da USER@CORP.LOCAL
# Paths to Domain Controllers
runoff -p 'pass' path dc USER@CORP.LOCAL
# Paths between any two nodes
runoff -p 'pass' path to USER@CORP.LOCAL 'DOMAIN ADMINS@CORP.LOCAL'
# Show up to 5 paths with detailed edge info
runoff -p 'pass' path da USER@CORP.LOCAL -n 5 -dMark compromised principals and run targeted queries from your current foothold:
# Mark a principal as owned
runoff -p 'pass' mark owned USER@CORP.LOCAL
# Mark as tier zero
runoff -p 'pass' mark tier-zero DC01.CORP.LOCAL
# List all owned principals
runoff -p 'pass' owned
# List tier zero assets
runoff -p 'pass' tierzero
# Unmark
runoff -p 'pass' unmark owned USER@CORP.LOCAL
# Clear all owned markings
runoff -p 'pass' clear owned
# Run queries that leverage owned principals
runoff -p 'pass' run ownedExploitation commands alongside every finding -- Impacket, Certipy, bloodyAD, Rubeus -- loaded from YAML templates with auto-substituted targets and domains:
# Enable abuse commands for any query run
runoff -p 'pass' --abuse run acl adcs9 template files cover ACL abuse, ADCS attacks, credential attacks, delegation, coercion, GPO abuse, group abuse, and lateral movement.
# Group members (recursive)
runoff -p 'pass' members 'DOMAIN ADMINS@CORP.LOCAL'
# What groups does a user belong to
runoff -p 'pass' memberof USER@CORP.LOCAL
# Who has admin rights on a machine
runoff -p 'pass' adminto DC01.CORP.LOCAL
# Where does a user have admin rights
runoff -p 'pass' adminof USER@CORP.LOCAL
# Active sessions
runoff -p 'pass' sessions DC01.CORP.LOCAL
# Attack edges from/to a node
runoff -p 'pass' edges from USER@CORP.LOCAL
runoff -p 'pass' edges to DC01.CORP.LOCALTable, JSON, CSV, HTML, and Markdown reports. Structured output goes to stdout, status/progress to stderr for clean piping:
# JSON export
runoff -p 'pass' -o json run all > results.json
# CSV for spreadsheet analysis
runoff -p 'pass' -o csv run all > results.csv
# HTML report
runoff -p 'pass' -o html run all > report.html
# Markdown tables
runoff -p 'pass' -o markdown run all
# Write to file directly
runoff -p 'pass' -o json -O results.json run allCompare two JSON result files to track remediation progress:
runoff -p 'pass' -o json run all > before.json
# ... remediation happens ...
runoff -p 'pass' -o json run all > after.json
runoff diff before.json after.jsonIngest SharpHound data and view collection history without opening a browser. Uses HMAC-authenticated requests to the BloodHound CE REST API (separate from the Neo4j Bolt connection used for queries).
# Set up API authentication (stores token in ~/.config/runoff/runoff.ini)
runoff auth
# Ingest SharpHound/AzureHound data
runoff ingest files data.zip
# View ingestion history
runoff ingest historyDrop custom query files in ~/.config/runoff/queries/ for organization-specific checks:
# Enable plugin loading
runoff -p 'pass' --load-plugins run allCustom queries use the same @register_query decorator as built-in queries.
Save defaults to ~/.config/runoff/config.yaml so you don't repeat flags:
bolt_uri: bolt://127.0.0.1:7687
username: neo4j
password: bloodhoundcommunityedition
domain: CORP.LOCAL
output_format: table
severity: critical,high
abuse: true| Variable | Description |
|---|---|
RUNOFF_BOLT_URI |
Neo4j Bolt URI |
RUNOFF_USERNAME |
Neo4j username |
RUNOFF_PASSWORD |
Neo4j password |
RUNOFF_DOMAIN |
Domain filter |
XDG_CONFIG_HOME |
Override config directory base |
Priority: CLI flags > environment variables > config file > defaults.
| Flag | Description | Default |
|---|---|---|
-b, --bolt |
Neo4j Bolt URI | bolt://127.0.0.1:7687 |
-u, --username |
Neo4j username | neo4j |
-p, --password |
Neo4j password | bloodhoundcommunityedition |
-d, --domain |
Domain filter | all domains |
-o, --output |
Output format (table, json, csv, html, markdown) | table |
-O, --output-file |
Write output to file | stdout |
-s, --severity |
Severity filter (comma-separated) | all |
--abuse / --no-abuse |
Show exploitation commands | off |
-q, --quiet |
Suppress banner and info | off |
--no-color |
Disable color output | off |
--debug |
Enable debug output | off |
--load-plugins |
Load custom queries from plugin dir | off |
| Command | Description |
|---|---|
run <categories...> |
Run queries by category (e.g. run all, run acl adcs) |
query [name] |
Run a single query by name, or list queries with -l |
queries |
List all registered queries with metadata |
audit |
Full security audit |
quickwins |
High-impact quick wins |
stats |
Domain statistics overview |
diff <file1> <file2> |
Compare two JSON result files |
kerberoastable |
Kerberoastable users |
asrep |
AS-REP roastable accounts |
unconstrained |
Unconstrained delegation |
nolaps |
Computers without LAPS |
computers |
All domain computers |
users |
All domain users |
spns |
Service principal names |
info <node> |
Node properties and details |
search <pattern> |
Search nodes by name pattern |
investigate <node> |
Full node investigation (supports * wildcards) |
path da <source> |
Shortest path to Domain Admins |
path dc <source> |
Shortest path to Domain Controllers |
path to <source> <target> |
Shortest path between two nodes |
mark <type> <nodes...> |
Mark nodes as owned or tierzero |
unmark <type> <nodes...> |
Remove markings |
owned |
List all owned principals |
tierzero |
List tier zero assets |
clear owned |
Clear all owned markings |
clear db |
Clear entire database |
members <group> |
Recursive group members |
memberof <node> |
Group memberships |
adminto <computer> |
Who has admin rights on a machine |
adminof <principal> |
What computers a principal can admin |
sessions <node> |
Active sessions on a machine |
edges from <node> |
Outbound attack edges |
edges to <node> |
Inbound attack edges |
status |
Test Neo4j connection |
domains |
List all domains in the database |
auth |
Set up BloodHound CE API credentials |
ingest files <file...> |
Upload SharpHound data to BloodHound CE |
ingest history |
View ingestion history |
completion |
Generate shell completion (bash/zsh/fish) |
runoff/
├── cli/ # Click CLI -- 33 commands across 11 modules
│ ├── commands/ # Command implementations
│ │ ├── queries.py # run, query, queries
│ │ ├── filters.py # kerberoastable, asrep, quickwins, etc.
│ │ ├── nodes.py # info, search, investigate
│ │ ├── paths.py # path da/dc/to
│ │ ├── marking.py # mark, unmark, owned, tierzero, clear
│ │ ├── membership.py # members, memberof, adminto, adminof, sessions
│ │ ├── edges.py # edges from/to
│ │ ├── connection.py # status, domains
│ │ ├── api.py # auth, ingest
│ │ └── diff.py # diff
│ ├── context.py # Neo4j connection management
│ └── defaults.py # Config file loading
├── core/ # Neo4j integration
│ ├── bloodhound.py # BloodHoundCE class -- Bolt driver, Cypher queries, path finding
│ ├── config.py # Global config singleton
│ └── cypher.py # Cypher query utilities
├── queries/ # 183 queries in 15 category folders
│ ├── base.py # @register_query decorator, QUERY_REGISTRY
│ ├── acl/ # ACL abuse, shadow admins, LAPS readers
│ ├── adcs/ # ADCS ESC1-15, certificate templates
│ ├── azure/ # AAD Connect, hybrid attack surface
│ ├── credentials/ # Kerberoasting, AS-REP, DCSync, GMSA
│ ├── delegation/ # Unconstrained, constrained, RBCD
│ ├── domain/ # Trusts, functional levels, domain stats
│ ├── exchange/ # Exchange permissions, delegation
│ ├── gpo/ # GPO abuse, tier-zero GPOs
│ ├── groups/ # Dangerous groups, protected users
│ ├── hygiene/ # Stale accounts, signing, LAPS coverage
│ ├── lateral/ # RDP, PSRemote, DCOM, sessions
│ ├── misc/ # Duplicate SPNs, circular groups
│ ├── owned/ # Paths from owned principals
│ └── paths/ # Attack paths, busiest paths
├── abuse/ # YAML exploitation templates (9 files)
│ └── templates/ # ACL, ADCS, credentials, delegation, coercion, GPO, groups, lateral, Azure
├── display/ # Rich output rendering (Catppuccin Mocha)
│ ├── tables.py # Table formatting
│ ├── panels.py # Panel helpers
│ ├── report.py # HTML report generation
│ ├── output.py # JSON, CSV, HTML, Markdown emitters
│ └── summary.py # Executive summary
└── api/ # BloodHound CE REST API (ingestion only)
├── client.py # HMAC-authenticated HTTP client
├── config.py # API credentials (~/.config/runoff/runoff.ini)
└── ingest.py # File upload
| Capability | Linux | macOS | Windows |
|---|---|---|---|
| CLI | Full | Full | Full |
| Neo4j Connection (Bolt) | Full | Full | Full |
| Rich Terminal UI | Full | Full | Full (Windows Terminal recommended) |
| BloodHound CE API | Full | Full | Full |
| Shell Completion | bash, zsh, fish | bash, zsh, fish | Limited |
| JSON/CSV/HTML Export | Full | Full | Full |
Report security issues via GitHub Security Advisories. Responsible disclosure timeline: 90 days.
Runoff does not:
- Touch Active Directory -- queries data already collected by BloodHound
- Store or exfiltrate domain credentials
- Perform network scanning or active reconnaissance
- Execute commands remotely or manage implants
MIT -- Copyright 2026 Real-Fruit-Snacks