SkillAgentSearch skills...

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/ForceHound

README

ForceHound

CI Python 3.9+ License: BSD-3-Clause

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.

ForceHound graph in BloodHound CE

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 client
  • aiohttp >= 3.9.0 — Async HTTP for Aura endpoints
  • pytest >= 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>.json for 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

View on GitHub
GitHub Stars36
CategoryDevelopment
Updated1d ago
Forks2

Languages

Python

Security Score

95/100

Audited on Apr 7, 2026

No findings