Data Model
SFHound maps Salesforce’s identity and permission model as a typed property graph compatible with BloodHound OpenGraph v2. This page is the authoritative reference for every node and edge type.
Node types
| Node | Label | Description | Icon | Colour |
|---|---|---|---|---|
| Organisation | SFOrganization | Top-level org container. System permissions are modelled as edges to this node. | building | #2d3436 |
| User | SFUser | A Salesforce user principal (human or service account). | user | #00b894 |
| Profile | SFProfile | The baseline permission assignment; every user has exactly one. | user-gear | #0984e3 |
| Permission Set | SFPermissionSet | Additive permissions that can be stacked on a user above their Profile. | id-badge | #7f8c8d |
| Permission Set Group | SFPermissionSetGroup | A named bundle of one or more Permission Sets. | users | #fdcb6e |
| Role | SFRole | A position in the role hierarchy, determining record visibility upward. | sitemap | #6c5ce7 |
| Public Group | SFGroup | A named collection of users and/or nested groups used in sharing rules. | users | #fdcb6e |
| Queue | SFQueue | A group-like object that can own records of configured SObject types. | inbox | #e17055 |
| Connected App | SFConnectedApp | An OAuth application registered in the org. | plug | #00cec9 |
| SObject | SFSObject | A Salesforce object (standard or custom) with CRUD and sharing metadata. | database | #636e72 |
| Field | SFField | A field on an SObject. Field-Level Security edges target these nodes. | list-check | #e84393 |
Key node properties
SFUser
{ "Id": "005...", "name": "JANE DOE", "Username": "jane.doe@example.com", "IsActive": true, "ProfileId": "00e...", "UserRoleId": "00E..."}SFPermissionSet / SFProfile
{ "Id": "0PS...", "name": "Custom_API_Integration", "IsOwnedByProfile": false, "PermissionsModifyAllData": false, "PermissionsAuthorApex": true}SFSObject
{ "name": "SECRETDATA__C", "Label": "Secret Data", "IsCustom": true, "InternalSharingModel": "Private", "ExternalSharingModel": "Private"}Edge types
Assignment edges
| Edge | Source | Target | Description |
|---|---|---|---|
AssignedProfile | SFUser | SFProfile | User is assigned to this Profile |
AssignedPermissionSet | SFUser | SFPermissionSet | User has this Permission Set directly assigned |
AssignedPermissionSetGroup | SFUser | SFPermissionSetGroup | User has this Permission Set Group assigned |
HasPermissionSet | SFProfile | SFPermissionSet | Profile is backed by its own PermissionSet record (IsOwnedByProfile=true) |
IncludesPermissionSet | SFPermissionSetGroup | SFPermissionSet | Permission Set Group includes this Permission Set |
Role hierarchy edges
| Edge | Source | Target | Description |
|---|---|---|---|
HasRole | SFUser | SFRole | User is assigned to this role |
InheritsRole | SFRole | SFRole | Child role — users in the parent role can see records owned by users in this child role |
Group & queue edges
| Edge | Source | Target | Description |
|---|---|---|---|
MemberOfGroup | SFUser / SFGroup | SFGroup / SFQueue | Direct or nested group/queue membership |
HasMember | SFGroup / SFQueue | SFUser / SFGroup | Inverse of MemberOfGroup |
CanOwnObject | SFQueue | SFSObject | Queue is configured to own records of this SObject type |
Object permission (CRUD) edges
All sourced from SFProfile or SFPermissionSet, all target SFSObject.
| Edge | What it means |
|---|---|
CanCreate | Can create new records |
CanRead | Can read records (subject to sharing) |
CanEdit | Can edit records (subject to sharing) |
CanDelete | Can delete records (subject to sharing) |
CanViewAll | Can view all records — bypasses sharing rules |
CanModifyAll | Can edit/delete all records — bypasses sharing rules |
Field-Level Security (FLS) edges
All sourced from SFProfile or SFPermissionSet, all target SFField.
| Edge | What it means |
|---|---|
IsVisible | Field is readable and editable (PermissionsEdit=true) |
ReadOnly | Field is readable but not editable (PermissionsRead=true, PermissionsEdit=false) |
System permission edges
All sourced from SFProfile or SFPermissionSet, all target SFOrganization.
| Edge | Risk level | What it grants |
|---|---|---|
ModifyAllData | 🔴 Critical | Modify every record in the org — bypasses all sharing |
ViewAllData | 🔴 Critical | Read every record — bypasses all sharing; exfiltration risk |
ManageUsers | 🔴 High | Create, edit, activate, and deactivate users |
AuthorApex | 🔴 High | Create and deploy Apex code — arbitrary server-side execution |
CustomizeApplication | 🔴 High | Customise Salesforce application metadata |
ManageProfilesPermissionsets | 🔴 High | Manage profiles and permission sets |
ManageSharing | 🔴 High | Manage sharing rules and OWD settings |
ManageRoles | 🟠 Medium | Create and edit the role hierarchy |
ManageTranslation | 🟠 Medium | Rename fields and labels org-wide |
EditTask | 🟡 Low | Edit Task records owned by others (sharing-gated) |
EditEvent | 🟡 Low | Edit Event records owned by others (sharing-gated) |
ViewSetup | ℹ️ Info | View setup and configuration |
ApiEnabled | ℹ️ Info | All programmatic API access (REST, SOAP, Bulk, Metadata, Tooling) |
OAuth & provenance edges
| Edge | Source | Target | Traversable | Description |
|---|---|---|---|---|
CanAuthorize | SFProfile / SFPermissionSet | SFConnectedApp | Yes | Profile or PermSet grants OAuth-authorise right for this app |
CreatedBy | SFConnectedApp | SFUser | No | Records the admin who created the Connected App (audit/provenance) |
Edge context properties
Every named edge type carries the following properties, visible in the BloodHound edge detail panel:
| Property | Description |
|---|---|
General | What the edge represents and how the permission works |
AbuseInfo | How an attacker exploits this edge — escalation paths, blast radius, prerequisites |
RemediationInfo | Actionable steps to restrict or remediate access, with SOQL audit queries |
OPSEC | What is and is not logged when this edge is exercised |
References | MITRE ATT&CK technique mapping and Salesforce documentation URLs |
Design decisions
See the Design Decisions section for the rationale behind key modelling choices:
- System permissions as edges, not node properties
- Aggregate PermissionSet placeholder hydration
- Shared
sobject_lookupfor queue and CRUD edges