Scott Covert

With Halloween just around the corner, we thought it would be a good time to share a Salesforce-themed costume you can find right inside your org.

Hiding in Plain Sight

By now, it will likely come as no surprise that Salesforce announced permissions on profiles will be retired with the Spring ‘26 release. What may come as a suprise, however, is just how much they have already done to prep admins for the transition to managing permissions via permission sets and permission set groups.

Here is the big reveal:

Every profile already has an underlying permission set with matching permissions.

Note that they are not visible from the UI so if you look for them alongside your other permission sets in the Setup menu you won’t find them. Similar to the sneaky ghosts in Super Mario Brothers, they don’t like when you look directly at them. :ghost:

However, you can shine the flashlight on them by running the following SOQL query:

list<PermissionSet> profilePermSets = [SELECT Id, Type, IsCustom, Profile.Name, ProfileId, Label, Name FROM PermissionSet WHERE IsOwnedByProfile = true];

If you debug the output of the preceding SOQL query you’ll see that each profile (custom and standard) has an underlying permission set. This even includes the Guest License User profile as well as every corresponding profile autogenerated with each Site/Community/Digital Experience you’ve created. Additionally, you’ll also note that the labels and names for many of these hidden permission sets are derived from the ids of the corresponding profiles.

for (PermissionSet profilePermSet : profilePermSets) {
  System.debug('PermSet: ' + profilePermSet.Label + ' Profile Id: ' + profilePermSet.ProfileId);

Every time you make a change to a profile, the underlying permission set will have its associated permissions updated as well–that’s pretty cool considering we can’t currently create trigger logic on profiles and permission sets ourselves (yet…)

So there you have it, your profiles are all wearing permission set masks and you didn’t even know it–boo! :scream:

Trick or Treat?

Unfortunately, these permission sets are not available for assignment to your users. If you run the following anonymous Apex:

PermissionSet ps = [SELECT Id FROM PermissionSet WHERE IsOwnedByProfile = true LIMIT 1];
PermissionSetAssignment psa = new PermissionSetAssignment(AssigneeId = UserInfo.getUserId(), PermissionSetId = ps.Id);
insert psa;

then you will see the following error:

You can't assign or unassign this permission set because it's associated with a profile

You could create a clone of a profile-owned permission set, but then you’d lose the automatic updates provided by Salesforce so likely this would do more harm than good.

According to an old post from a Salesforce PM on StackExchange:

…we only allow query-ability of profiles and their assignments using the permissionset and permissionsetassignment sobjects. The intent was to enable the creation of administrative visualization tools on top of our API to address the question, ‘Why does this user have this permission.’

That post was made ten years ago, but it still seems to hold true. Even still, hopefully you’ll find these hidden permission sets useful as you prepare for the retirement of permissions on profiles.

If you’re interested in other ways to get a handle on permissions in your Salesforce org, the team at Tython has been building out a Permissions Assistant tool. Feel free to give us a shout and we’d be happy to show it to you!