ForceHound
Salesforce identity and permission graph collector for BloodHound CE. Maps users, profiles, permission sets, roles, groups, sharing rules, connected apps, and field-level security into attack-path graphs.
Install / Use
/learn @NetSPI/ForceHoundREADME
ForceHound
Unified Salesforce BloodHound Collector
ForceHound maps Salesforce identity, permission, and access-control structures into an attack-path graph compatible with BloodHound Community Edition. It outputs OpenGraph v1 JSON that can be ingested by BloodHound CE to discover privilege-escalation paths, over-permissioned accounts, and hidden lateral-movement opportunities inside a Salesforce org.

Two collection backends are available and can be used independently or together:
| Backend | Auth Required | Library | Best For |
|---------|--------------|---------|----------|
| API (REST) | Admin session or username/password | simple_salesforce | Full org enumeration with Share objects |
| Aura (Lightning) | Browser session tokens | aiohttp | Low-privilege recon without admin access |
Installation
# Clone and install in editable mode
cd ForceHound_v0.1
pip install -e .
# Or install from requirements.txt
pip install -r requirements.txt
Requirements: Python 3.9+
Dependencies:
simple-salesforce >= 1.12.0— Salesforce REST API clientaiohttp >= 3.9.0— Async HTTP for Aura endpointspytest >= 7.0— Test framework *pytest-asyncio >= 0.21— Async test support *
* Development/test dependencies only. Install with pip install -e ".[dev]"
Quick Start: Data Collection
Aura Mode (Low-Privilege)
Collect using Lightning Aura endpoints. Requires a browser session — no admin access needed.
python -m forcehound --collector aura \
--instance-url https://myorg.lightning.force.com \
--session-id "00DXX0000001234!AQEAQ..." \
--aura-context '{"mode":"PRODDEBUG","fwuid":"...","app":"..."}' \
--aura-token "eyJ..." \
-o aura_output.json -v
API Mode (Privileged)
Collect using the Salesforce REST API. Requires admin-level access.
# With session ID
python -m forcehound --collector api \
--instance-url https://myorg.my.salesforce.com \
--session-id "00DXX0000001234!AQEAQ..." \
-o api_output.json -v
# With username/password
python -m forcehound --collector api \
--instance-url https://myorg.my.salesforce.com \
--username admin@myorg.com \
--password "P@ssw0rd" \
--security-token "aBcDeFgH" \
-o api_output.json -v
Both Mode (Merged)
Run both backends and merge results into a single graph. Produces the most complete picture.
python -m forcehound --collector both \
--instance-url https://myorg.lightning.force.com \
--session-id "00DXX0000001234!AQEAQ..." \
--aura-context '{"mode":"PRODDEBUG","fwuid":"..."}' \
--aura-token "eyJ..." \
--api-instance-url https://myorg.my.salesforce.com \
--api-session-id "00DXX0000001234!AQEAQ..." \
-o both_output.json -v
Output is saved to the file specified by -o (default: forcehound_output.json).
Quick Start: BloodHound Sync
Once you have a graph JSON file, upload it to BloodHound CE for visualization.
One-Time Setup
# Register ForceHound's custom node types and icons in BloodHound CE
python -m forcehound --setup \
--bh-token-id "your-token-uuid" \
--bh-token-key "your-base64-key"
Note: You need a running BloodHound CE instance. See BloodHound CE setup instructions to install it on your localhost.
Collect and Upload in One Step
python -m forcehound --collector aura \
--instance-url https://myorg.lightning.force.com \
--session-id "..." --aura-context "..." --aura-token "..." \
--crud --audit-log 3 \
--upload --clear-db \
--bh-token-id "your-token-uuid" \
--bh-token-key "your-base64-key"
Useful Cypher Queries
Once data is ingested, open the BloodHound CE Cypher console and try these:
-- All users with ModifyAllData (admin-equivalent)
MATCH (u:SF_User)-[:HasProfile|HasPermissionSet]->(e)-[:ModifyAllData]->(o:SF_Organization)
RETURN u.name, labels(e)[0], e.name
-- Shortest path from any user to ModifyAllData
MATCH p=shortestPath((u:SF_User)-[*1..5]->(o:SF_Organization))
WHERE ANY(r IN relationships(p) WHERE type(r) = 'ModifyAllData')
RETURN p
-- Users who can author Apex (remote code execution)
MATCH (u:SF_User)-[:HasProfile|HasPermissionSet]->(e)-[:AuthorApex]->(o:SF_Organization)
RETURN u.name, u.email, e.name
-- All CRUD-proven object access for the session user
MATCH (u:SF_User)-[r:CrudCanCreate|CrudCanRead|CrudCanEdit|CrudCanDelete]->(obj:SF_Object)
RETURN u.name, type(r), obj.name
Proxying Traffic
Route all ForceHound traffic through an HTTP proxy (e.g., Burp Suite):
python -m forcehound --collector aura \
--proxy http://127.0.0.1:8080 \
...
This applies to both the Aura (aiohttp) and API (simple_salesforce/requests) backends.
Rate Limiting
Throttle requests to a maximum number per second:
python -m forcehound --collector aura \
--rate-limit 5 \
...
CRUD Probing
ForceHound can empirically test Create, Read, Edit, and Delete permissions by actually attempting DML operations against the org via Aura. This goes beyond metadata — it proves what the current session user can actually do.
See forcehound/collectors/crud/dummy_values.py for the sample values submitted during CRUD probing.
Standard Mode
python -m forcehound --collector aura \
--instance-url https://myorg.lightning.force.com \
--session-id "..." --aura-context "..." --aura-token "..." \
--crud -v
- Read: Enumerates records from every accessible object
- Create: Builds dummy records using intelligent field population (auto-resolves lookup references, respects picklists, handles required fields)
- Edit: No-op save/restore on one record per object
- Delete: Cleans up self-created records only (reverse dependency order)
Aggressive Mode
python -m forcehound --collector aura \
... \
--crud --aggressive -v
- Edit: Attempts a no-op save/restore on every record in every accessible object
- Delete: Deletes one random existing record per object (full pre-deletion snapshot saved to
forcehound_deletions_<timestamp>.jsonfor recovery) - Protected objects (User, Profile, PermissionSet, ApexClass, etc.) are excluded from deletion by default
Unsafe Mode
python -m forcehound --collector aura \
... \
--crud --aggressive --unsafe -v
Allows delete-probing of protected identity/config objects. Even with --unsafe, only the self-created record is deleted — existing records of protected objects are never touched.
Additional CRUD Options
--crud-objects Account,Contact Only probe specific objects
--crud-dry-run Log plan without executing DML
--crud-concurrency 5 Max concurrent CRUD requests (default: 5)
--crud-max-records 10 Cap records tested per object in aggressive edit
CRUD Edges
CRUD probing emits four additional edge kinds:
| Edge | Meaning |
|------|---------|
| CrudCanCreate | Session user can create records of this object |
| CrudCanRead | Session user can read records of this object |
| CrudCanEdit | Session user can edit records of this object |
| CrudCanDelete | Session user can delete records of this object |
Protected Objects
The following objects are excluded from aggressive deletion (override with --unsafe):
Identity & access control: User, Profile, PermissionSet, PermissionSetGroup, PermissionSetGroupComponent, PermissionSetAssignment, Group, GroupMember, UserRole, Organization, CustomPermission, MutingPermissionSet
Auth & integration: ConnectedApplication, OauthToken, AuthProvider, NamedCredential
Apex code: ApexClass, ApexTrigger, ApexComponent, ApexPage
Aura / LWC: AuraDefinition, AuraDefinitionBundle
Visualforce & UI: StaticResource, FlexiPage
Flows: FlowDefinitionView, FlowRecord, FlowRecordVersion
Audit & logging: SetupAuditTrail, LoginHistory
Audit Logging
ForceHound includes audit logging that records every HTTP interaction with the Salesforce org. Audit logs are written as JSONL (one JSON object per line) aligned with the OCSF API Activity schema (class_uid 6003), enabling native ingestion by Splunk, Elastic, Microsoft Sentinel, AWS Security Lake, and other SIEM platforms.
python -m forcehound --collector aura \
... \
--audit-log 3 -v
Audit Levels
| Level | Content | Use Case | |-------|---------|----------| | 1 | Timestamp, operation, target resource, status code | Quick activity ledger | | 2 | + HTTP headers, duration, error detail, response state | Operational debugging | | 3 | + Full request body, full response body (no truncation) | Forensic reconstruction |
Audit Log Structure
- Session Start — ForceHound version, collector type, CLI arguments, org metadata
- Session User Resolved — Confirmed session user identity (UID, name)
- Per-request entries — Sequentially numbered, one per HTTP request
- Session End — Total entry count, request count, file size
Output: forcehound_audit_<timestamp>.jsonl
Warning: Level 3 logs contain the full session ID in request headers. Treat audit log files as credential artifacts.
CLI Reference
Connection
--collector {api,aura,both} Collection backend (default: aura)
Related Skills
healthcheck
352.9kHost security hardening and risk-tolerance configuration for OpenClaw deployments
node-connect
352.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
prose
352.9kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
claude-opus-4-5-migration
111.5kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
