Salesforce access debt rarely arrives in one dramatic change. A contractor finishes a project, a team reorganizes, or an admin clones a profile to move quickly — and the old permission set, profile grant, or sharing rule quietly stays behind. Over time, users can inherit access from several layers at once, while nobody can explain which layer is responsible for it.

This guide is a practical Salesforce security audit for permission-set bloat, profile sprawl, and sharing conflicts. It shows how to find orphaned permission sets, review years of incremental profile grants, and reason about organization-wide defaults (OWD), role hierarchy, sharing rules, manual sharing, territories, and “View All” or “Modify All” access without confusing one access model for another.

3 access layers · 1 effective result A user’s effective access is the combined result of object permissions, field permissions, and record-level sharing. The safest audit inventories each layer separately, then tests the paths that create unexpected access before changing anything.

1. Permission Set Bloat: Finding Orphaned and Unassigned Sets

Permission sets are meant to add a narrowly-scoped capability without cloning a profile. In practice, they accumulate as one-off grants: a temporary integration, a contractor project, a pilot permission, or a role that was renamed after a reorganization. A permission set becomes an orphaned set when it is no longer assigned to any active user or when its original business owner and purpose have disappeared.

Why permission sets accumulate after team changes

Reorganizations change roles and reporting lines faster than access inventories get updated. Contractor accounts are deactivated, but their project-specific permission sets remain. Admins also tend to create a new set for each urgent request instead of consolidating an existing grant. None of those actions is automatically wrong; the risk is losing the explanation for why the set exists.

Orphaned does not mean safe to delete Review

An unassigned set can still be part of a documented access package, a deployment source, or a planned onboarding workflow. Treat “zero assignments” as a review signal. Record the owner, intended population, last deployment, and permissions before deactivating or deleting it.

Setup path: Permission Set Assignments

In Setup, search for Permission Sets, open a set, and review its object permissions, field permissions, system permissions, and Manage Assignments list. Then open Users → Permission Set Assignments to review assignments from the user side. Check whether the assignee is active, whether the set is part of a permission set group, and whether the business purpose still exists.

Read-only SOQL inventory

In Workbench or the Developer Console Query Editor, start with the metadata object and assignment object separately. These queries only read metadata and assignments; they do not remove anything.

SELECT Id, Name, Label, IsOwnedByProfile, License.Name
FROM PermissionSet
WHERE IsOwnedByProfile = false
ORDER BY Label

The IsOwnedByProfile = false filter focuses on standalone permission sets rather than the permission-set records Salesforce creates for profiles. To see who receives a set, query assignments and include user status so deactivated users do not look like current consumers:

SELECT PermissionSetId, PermissionSet.Name, PermissionSet.Label,
       AssigneeId, Assignee.Name, Assignee.Username, Assignee.IsActive
FROM PermissionSetAssignment
WHERE PermissionSet.IsOwnedByProfile = false
ORDER BY PermissionSet.Label, Assignee.Name

Export both results and left-join the PermissionSet inventory to the assignment export. A set absent from the assignment result is unassigned; a set assigned only to inactive users is a different cleanup candidate. Confirm API version and object availability in your org before relying on a field, because Salesforce metadata visibility can vary by edition and release.

2. Profile Sprawl: When Years of Grants Become a Security Boundary

Profiles are the baseline for every user, so they are harder to change safely than an additive permission set. Years of incremental grants create profiles with broad object permissions, “View All” or “Modify All,” system permissions, and field access that no current job description requires. Cloned profiles make the problem harder to see because similar names can conceal different privileges.

Inventory permissions by profile, object, and field

In Setup, open Profiles, compare profiles with the same license and user population, and inspect Object Settings and Administrative Permissions. For a durable inventory, retrieve profile metadata with Metadata API or Salesforce CLI and create a matrix with one row per profile/object/field permission. Capture at least read, create, edit, delete, view all, modify all, and field-level read/edit values.

LayerAudit questionRisk signal
ProfileWhat is the baseline for this license and job family?Multiple cloned profiles with no documented difference
ObjectDoes the role need create, edit, delete, or all-record access?Modify All on sensitive objects
FieldWhich fields are readable or editable?FLS exposes sensitive fields by default
SystemWhich administrative actions can the user perform?ManageUsers, API, or setup permissions on non-admin roles

Compare a profile’s privileges with what users actually do, not only with its name. A “Sales Operations” profile that has accumulated View All Data is not merely untidy; it changes the blast radius of every integration, report export, and compromised session using that profile.

Profile-bloat review 5 checks

  • List every profile and its license, active user count, owner, and last review date.
  • Compare cloned profiles side by side and document every permission difference.
  • Flag View All, Modify All, API access, and setup permissions outside admin roles.
  • Review FLS for sensitive fields separately from object-level CRUD access.
  • Move additive, job-specific grants into named permission sets or permission set groups before narrowing a profile.

3. Sharing Conflicts: Separating OWD, Hierarchy, and Explicit Grants

Sharing conflicts are usually reasoning conflicts: an admin sees that a user can open a record and assumes a sharing rule granted it, or sees a private OWD and assumes the record must be inaccessible. Salesforce evaluates several record-level paths. Access is generally additive, so the most permissive applicable path wins; removing one path may not remove access if another remains.

Map the record-access layers in order

  1. OWD: Set the baseline for internal and external access to each object.
  2. Role hierarchy: Can managers inherit access to records owned by users below them?
  3. Sharing rules: Do owner-based or criteria-based rules open records to roles, groups, territories, or queues?
  4. Manual and Apex-managed sharing: Has a record been shared directly, or by code, outside the durable rule model?
  5. Territories and teams: Do account, opportunity, or territory teams add access that is easy to miss in a role review?
  6. Object-level overrides: Does the profile or permission set grant View All or Modify All, bypassing record-level restrictions for that object?

A private OWD does not override a sharing rule, and a sharing rule does not remove access granted by a profile or permission set. Likewise, role hierarchy access can coexist with an explicit share. Document the access path for a sample record before changing the rule that appears most suspicious.

Setup path: Sharing Settings and access tests

Start at Setup → Sharing Settings and record OWD, Grant Access Using Hierarchies, owner-based rules, criteria-based rules, and territory settings per sensitive object. Then use Sharing on an individual record to inspect the sharing details and test with a representative user. Compare the result with the user’s profile, permission sets, role, group memberships, and teams.

Access can be correct and still be unexpected Trace path

If a user can edit a record, the reason may be object-level Modify All, a role-hierarchy grant, an owner rule, a criteria rule, a territory, a team, a manual share, or an Apex-managed share. The remediation depends on the path. Do not weaken OWD or delete a sharing rule until you know which path supplied the access and which users rely on it.

4. Five Setup and SOQL Checks You Can Run Today

Check 1: Unassigned standalone permission sets

How to find it: Run the PermissionSet inventory and compare it with PermissionSetAssignment. In Setup, confirm the set has no planned owner or onboarding use. What good looks like: every active set has a named owner, purpose, review date, and current assignment rationale.

Check 2: Assignments to inactive users

How to find it: Filter the assignment export where Assignee.IsActive = false and review the set’s intended replacement population. What good looks like: deactivated-user assignments are removed through a controlled change, while the underlying set is retained only when it has a current owner.

Check 3: High-risk profile and permission grants

How to find it: Retrieve Profile and PermissionSet metadata, then flag administrative permissions and object grants such as ViewAllRecords and ModifyAllRecords. What good looks like: high-risk grants map to an approved admin, integration, or compliance role — not to a convenience clone.

Check 4: OWD and sharing-rule overlap

How to find it: In Setup → Sharing Settings, record each object’s OWD, hierarchy behavior, and rule targets. Use the Sharing Rules Auditor for a metadata export. What good looks like: every rule has a distinct target, criteria purpose, owner, and test user; redundant “all internal users” rules are consolidated.

Check 5: A representative record’s access path

How to find it: Pick one sensitive record and one user who should not edit it. Use the record’s Sharing detail, then inspect the user’s profile, permission sets, role, territories, teams, and groups. What good looks like: the team can name the exact path that grants access and can reproduce the result with a least-privilege test user.

SELECT Id, Name, Label, IsOwnedByProfile
FROM PermissionSet
WHERE IsOwnedByProfile = false
ORDER BY Name
LIMIT 500

These checks are read-only. They identify candidates; they do not prove that a set, profile permission, or sharing rule is unused. Keep an export of the baseline and test in a sandbox or with a representative user before any removal.

Trace the Access Debt Before It Becomes an Incident

The Founding Audit connects permission grants, user assignments, profile baselines, and sharing paths so your team can prioritize the access changes with the clearest blast radius.

5. A Staged Remediation Cadence

Access cleanup should be staged, dependency-checked, and reversible. Removing a permission-set assignment or changing a sharing rule is not the same as deleting an unused file. It can interrupt a workflow, break an integration, change a report population, or remove a legitimate manager’s access.

  1. Baseline: Export permissions, assignments, profile metadata, OWD, sharing rules, and a sample of access-test results.
  2. Classify: Mark each finding as orphaned, redundant, over-privileged, undocumented, or business-critical-but-unclear.
  3. Validate dependencies: Check flows, Apex, integrations, reports, permission set groups, territories, and onboarding documentation.
  4. Stage: Remove assignments or narrow grants in a sandbox or pilot group first; do not bulk-delete permission sets or sharing rules from a query result.
  5. Verify and monitor: Re-run the inventory, test representative users, watch login and integration errors, and record the new owner and review date.

Frequently Asked Questions

What is an orphaned permission set?
Usually, it is a standalone permission set with no current assignments or only assignments to inactive users. That is a review signal, not automatic proof that deletion is safe.

Can a permission set override a profile?
Permission sets add permissions; they do not generally subtract permissions already granted by a profile. To reduce access, narrow the profile or remove the additive assignment after validating dependencies.

Does private OWD stop a user with View All Records?
No. Object-level View All or Modify All can bypass record-level sharing for that object. Review object permissions before concluding that a sharing rule is responsible.

How often should a Salesforce security audit run?
Review access quarterly and after reorganizations, acquisitions, major deployments, contractor projects, or changes to OWD and role hierarchy. High-risk profiles and integration users deserve more frequent review.

Should I delete unused permission sets in bulk?
No. Preserve a baseline, confirm ownership and dependencies, remove assignments in a staged change, and delete only after the set has passed a documented retention window.

Continue Reading

Related audits

Explore the next scoped review

This guide provides context for a scoped conversation. The Org Health Assessment offers a broader review, while the Managed Salesforce Administration offer focuses on ongoing access and security administration questions. Scope and the final quote are confirmed after intake.