Toxic permissions on Salesforce: the combinations that create the risk

A toxic permission is almost never a dangerous privilege on its own. It is a combination of privileges that, one by one, all have a good reason to exist. That is why it survives access reviews, and why no native alert fires.

Updated

100 %
inside your org
0
outbound data by default
71/255
controls self-assessed
10 min
to install

What is a toxic permission?

A toxic permission is a set of privileges whose combination on a single account enables an action that none of those privileges enabled on its own. On Salesforce, the most common form pairs a broad read privilege, a write or export privilege, and the absence of a control that should have governed both.

The difficulty is not recognising a sensitive privilege — every administrator knows what Modify All Data does. It is seeing that it coexists, on the same profile, with API access enabled and without multi-factor authentication. Each element was granted at a different time, by a different person, for a legitimate reason.

Which combinations come up most often? Detector by detector

Each combination below carries the detector that measures it, its finding key and its threshold — the same standard of proof as the complementary list further down, so that none of the five is asserted without being checkable.

Full read access + bulk export

View All Data paired with an export privilege — Bulk API, weekly export, or an exportable report — gives an account the ability to extract the entire customer data set in a single operation. Neither privilege is abnormal: the first serves support, the second serves management oversight.

Detector DataExportRiskCollector · finding Security:DataExport:BulkExport · threshold: ViewAllData crossed with DataExport, ExportReport or ApiEnabled on the same active account — High finding as soon as more than 3 active accounts hold the combination

Full write access + API + no MFA

This is the combination most often cited in Salesforce incidents. Modify All Data and API access on an account that does not require a second factor turn a compromised credential into full access, with no human interaction and no interface trail. Integration accounts are particularly exposed: they are granted broad privileges because they automate, and they are spared MFA for the same reason.

Detector BlastRadiusCollector · finding Security:ToxicCombo · threshold: (ModifyAllData or ViewAllData) + ApiEnabled on an active account with no MFA signal — a missing signal counts against the account, never for it — Small business tier

User management + permission set assignment

An account that can create users and assign them permission sets can indirectly grant itself any privilege. This is privilege escalation in the strict sense, and it triggers no native alert.

Detector SecurityPostureCollector · finding Security:OverPrivilege:ManageUsers · threshold: number of “Manage Users” holders above the ceiling set in the admin screens (5 by default). The cross with permission-set assignment is not measured today: this combination is listed because it can be checked by hand, not because a detector produces it.

Guest access and communities

The guest profiles of Experience Cloud sites sometimes inherit object privileges that were never intended for them. A read privilege granted to a guest profile exposes the data to an unauthenticated visitor — that is access control, not site configuration.

Detector GuestExposureCollector · finding Security:GuestExposure · threshold: any object readable or writable by an Experience Cloud guest profile

Connected apps and dormant OAuth tokens

A connected app authorised two years ago keeps its token for as long as nobody revokes it. The question to ask is not “who has access?” but “which OAuth scopes were granted, to what, and who still uses them?”.

Detector ConnectedAppRiskCollector · finding Security:OAuthApp · threshold: dormant at 90 days, risk score from 40 — a full or refresh_token scope is worth 30 points on its own

Which other combinations are worth watching?

The blind spot

These combinations trigger no native alert. Salesforce permits them all: they are valid configurations. You discover them at the audit, or at the incident.

OrgGuardian Findings screen showing detected toxic combinations, with their target and priced exposure
A toxic combination, as it surfaces. The profile named, the rights accumulated, and the amount that follows.

Why does a manual review miss them?

An access review looks at privileges profile by profile. Yet a user accumulates one profile and any number of permission sets, each contributing its share. The effective privilege of an account is the sum of those layers, and that sum is displayed nowhere in a usable form.

A mid-sized org has dozens of profiles, hundreds of permission sets and thousands of users. The Cartesian product to be examined exceeds what a quarterly review can cover — and it changes between two reviews.

How do you spot them at scale?

What can be read, and where. An account's effective privilege is the union of its profile and its permission sets: it is rebuilt from three objects — PermissionSet (which also carries profiles, IsOwnedByProfile = true), PermissionSetAssignment (linking each set to each user) and User (for active state, licence and last login). The fields PermissionsModifyAllData, PermissionsViewAllData, PermissionsApiEnabled and PermissionsManageUsers are read directly on PermissionSet. MFA state comes from the permission set carrying “Multi-Factor Authentication for User Interface Logins” and from the profile's session settings.

What the native interface can do: list the permission sets that carry a given privilege (Setup › Permission Sets, filtered on a permission), and list the users of one set. Where it stops: no screen shows a user's union of profile and sets, none crosses two privileges, none crosses a privilege with MFA state. A standard report on PermissionSetAssignment returns the raw list — several thousand rows on a 500-user org — without aggregating it.

The procedure, then: (1) extract PermissionSetAssignment joined to PermissionSet for only those sets carrying at least one broad privilege; (2) aggregate per user to obtain effective privilege; (3) keep only combinations — an isolated privilege is not a finding; (4) join MFA state and licence, to separate the human account from the integration account; (5) replay on every assignment change, not on every audit. That is exactly what BlastRadiusCollector does, with a ceiling of 5,000 assignments per pass beyond which the finding says it truncated rather than going quiet — and a missing row can make it miss a combination, never invent one.

How long does it take to audit an org?

By hand, on an org of a few hundred users, a serious review of effective privileges is counted in days — and it is out of date the next day. Instrumented, the same measurement is replayed at every scan, which shifts the effort from collection to decision.

What should be done with a toxic permission once it has been found?

Rarely remove it outright: it serves a purpose. The useful order is to determine who actually uses it, to cover the risk with a compensating control — mandatory MFA, IP address restriction, reduced OAuth scope — then to withdraw what is no longer in use. That is why a detection tool must remain read-only: the decision to withdraw a privilege in production belongs to the human who knows how it is used.

Author

Stéphane Berthoz

Builds and maintains OrgGuardian, the Salesforce managed package published by DOPAMINE SAS. Everything described here comes from building the tool, not from reading about it.

Have your org measured See the console

Reply within one business day

Your toxic combinations, named one by one.

The combinations described here are the ones OrgGuardian looks for in your org, and names. The first scan is read-only: it detects and advises, it never remediates in your place.

Or by e-mail: contact@orgguardian.com