Fix Guides

Audit and Reduce “Modify All Data” and “View All Data” in Salesforce

Updated 2026-11-06

Short version: Modify All Data and View All Data are user permissions stored as the boolean fields PermissionsModifyAllData and PermissionsViewAllData on PermissionSet. Profiles, permission sets and permission set groups can all carry them. One query lists the permission sets, one lists the users, and the Setup Audit Trail shows who changed them. Then replace each grant with object permissions.

Why audit them

These are the broadest data permissions in the platform. They are not scoped to an object or to a sharing rule, so one stray grant gives a user, or an integration credential, org-wide reach. An unmanaged list of holders is also hard to defend in an access review.

Symptoms

  1. 1. A security review or auditor asks who can see or change all data. Both permissions bypass record sharing, so the answer has to come from the permission data, not from role or sharing rules.
  2. 2. Nobody can say why a profile has the permission. Profiles accumulate it over years: an integration, a one-off data fix or an admin clone. The Setup Audit Trail shows recent changes, but not the original reason.
  3. 3. Integration and service users hold it by default. A user created for a sync tool is often given a broad profile so the first run works, and it is never narrowed afterwards.
  4. 4. A permission set group contains a permission set that carries it. Users assigned only the group show up in no profile-based report, so a profile-only review under-counts holders.

How to find who holds them

Run these in Developer Console, Workbench or the Salesforce CLI.

1. Permission sets, profiles and groups that carry either permission

SELECT Id, Label, Name, IsOwnedByProfile, Profile.Name, PermissionSetGroupId,
       PermissionsModifyAllData, PermissionsViewAllData
FROM PermissionSet
WHERE PermissionsModifyAllData = true OR PermissionsViewAllData = true

2. Users assigned to them

SELECT Assignee.Username, Assignee.IsActive, Assignee.Profile.Name,
       PermissionSet.Label, PermissionSet.IsOwnedByProfile, PermissionSetGroupId,
       PermissionSet.PermissionsModifyAllData, PermissionSet.PermissionsViewAllData
FROM PermissionSetAssignment
WHERE PermissionSet.PermissionsModifyAllData = true
   OR PermissionSet.PermissionsViewAllData = true
ORDER BY Assignee.Username

3. Which permission set inside a group is responsible

SELECT PermissionSetGroup.DeveloperName, PermissionSet.Label
FROM PermissionSetGroupComponent
WHERE PermissionSet.PermissionsModifyAllData = true
   OR PermissionSet.PermissionsViewAllData = true

4. Who changed permission sets (Setup Audit Trail)

SELECT CreatedDate, CreatedBy.Name, Action, Section, Display
FROM SetupAuditTrail
WHERE Action LIKE 'PermSet%'
ORDER BY CreatedDate DESC

The Setup Audit Trail page in Setup shows the same data and can be downloaded as CSV. Run these queries in a sandbox first if you are unsure; they only read data.

What to check

  1. 1. List every permission set that carries either permission. Run the first query below in Developer Console, Workbench or the CLI. Per the PermissionSet object reference, every permission is a boolean field on PermissionSet, and since API version 25.0 each profile has an owned permission set, so IsOwnedByProfile = true rows are profiles. PermissionSetGroupId is set when the permission set is owned by a permission set group.
  2. 2. List the users who hold them. Query PermissionSetAssignment filtered on the same two fields through the PermissionSet relationship. Per the object reference, AssigneeId points at the user and an assignment names either a PermissionSetId or a PermissionSetGroupId. Note that a user's profile is not a PermissionSetAssignment row you filter on separately here: the profile-owned permission set is what the query matches, so profile holders are included.
  3. 3. Look inside permission set groups. The PermissionSet reference says a group's permission set contains the aggregated permissions of the group, so group holders appear in the second query. To find which component permission set causes it, query PermissionSetGroupComponent. Check the result against Setup before relying on it, and check how muting permission sets are treated in your org.
  4. 4. Separate active people from stale and system users. Group the rows by Assignee.IsActive and by profile. Inactive users still holding the permission are cleanup. Integration, automation and package users need a deliberate decision, not a bulk removal.
  5. 5. Read the Setup Audit Trail. Per the SetupAuditTrail reference it records Setup changes for at least the last 180 days. The Action field is a category such as PermSetCreate, and Display has the full description. Display is not filterable in SOQL, so filter on Action and Section, then read Display. For longer history, download the trail regularly or send it to your logging system.
  6. 6. Record each holder's reason. For every holder write the owner, the business reason and the date reviewed. A holder with no reason is the first removal candidate.

How to replace them with narrower access

  1. 1. Decide what each holder actually needs. Ask what task the permission is there for: reading records for reporting, mass updates, data loads, an integration, or an admin job. Most of these need object-level access, not org-wide access.
  2. 2. Replace with object permissions. On a permission set, grant Read, Edit and Delete on specific objects, and use the object-level View All Records or Modify All Records only on the objects that need it. Query ObjectPermissions (last query below) to see what a permission set already grants, and use it to build the replacement.
  3. 3. Move access into a permission set, not the profile. Create a narrow permission set for the task and assign it. This keeps the base profile minimal and makes the grant visible, reviewable and removable. Use an expiration date on the assignment for temporary access: PermissionSetAssignment has an ExpirationDate field from API version 52.0.
  4. 4. Test in a sandbox first. Create a test user with the narrower access and run the real job: the report, the data load, the integration call. Missing access shows up as insufficient-access errors; see our guide to the cross-reference entity error if you hit it.
  5. 5. Remove the permission, then monitor. Untick Modify All Data or View All Data on the permission set or profile, deploy, and watch Login History and integration logs for a few days. Keep the rollback to one change.
  6. 6. Make it a recurring check. Re-run the holder query on a schedule and compare the list. A new holder should come with an owner and a reason.

See what a permission set already grants on each object

SELECT Parent.Label, SobjectType, PermissionsRead, PermissionsEdit,
       PermissionsViewAllRecords, PermissionsModifyAllRecords
FROM ObjectPermissions
WHERE ParentId = '<permission set id>'

Check your org's permission posture free: the free health check is a short questionnaire that gives a peer-benchmarked score, with no account and no org connection. Related guides: permission set assignment failures, integration user recovery and insufficient access errors.

Sources: Salesforce Developer Docs object references for PermissionSet, PermissionSetAssignment and SetupAuditTrail, read on Nov 6, 2026. Field names and access requirements are from those pages; confirm in the live docs.

FAQ

What are the API field names?

PermissionsModifyAllData and PermissionsViewAllData on the PermissionSet object. Per the PermissionSet object reference, there is one boolean field per permission, and profiles are covered through their owned permission set (IsOwnedByProfile).

Who can run these queries?

Per the object references, access to PermissionSet requires one of View Setup and Configuration, Manage Session Permission Set Activations, Assign Permission Sets or Manage Profiles and Permission Sets, and PermissionSetAssignment requires View Setup and Configuration, Assign Permission Sets or Manage User.

Do these queries include profiles?

Yes, through the profile-owned permission set. The PermissionSet reference says every profile is associated with a permission set that stores its user permissions, and that you can query but not modify those. To change a profile, edit the profile.

How far back does the Setup Audit Trail go?

The SetupAuditTrail reference says at least the last 180 days.

Can I just remove the permission?

Not blindly. Anything that relied on it, such as an integration or a scheduled job running as that user, can start failing. Replace first, test in a sandbox, then remove.

Does Wrenk check this?

Wrenk's health check looks at over-permissioned users as part of its security findings. A check that cannot read the permission data is reported as not assessed, never as a pass.

What did we not verify?

We could not render the Salesforce Help articles for the user-permission descriptions or the Setup Audit Trail while writing this on Nov 6, 2026, so the field names, access requirements and 180-day retention come from the Salesforce developer object references linked below. The queries were not run against a live org for this page; run them in a sandbox first. We state no statistics about how common these permissions are.

Wrenk runs this kind of audit and the fixes that follow across every connected org as part of managed Salesforce operations.