Unauthorised access to data is a primary concern of clients who commission a Salesforce assessment. The Salesforce documentation acknowledges that the sharing model is a “complex relationship between role hierarchies, user permissions, sharing rules, and exceptions for certain situations”[1]. It is often said that complexity and security are natural enemies. Salesforce empowers its users with a multifaceted sharing framework in order to cover a wide variety of business use cases. But with great power comes great responsibility.
This blog post announces the release of a new open-source tool, Raccoon (https://www.github.com/nccgroup/raccoon), which aims to identify potential misconfigurations that could expose sensitive data within Salesforce. Specifically, it reveals where access has been granted to all records for particular objects of interest.
Before we go any further, it’s worth taking a step back and establishing the scene. To borrow the usual database analogy, you can think of a Salesforce ‘object’ as a database table and ‘records’ as rows in that table. Let’s consider a custom object called ‘Customer’, which includes sensitive fields. It may be perfectly acceptable that Adam from Sales has create, read and edit permissions on the Customer object itself. Without these, Adam could not create new Customers and later make changes to them. However, let’s say that Adam shouldn’t be able to see every Customer in the organisation – only those he owns by virtue of creating them. This is the normal run of things. In a Salesforce context, ‘sharing’ is all about extending access to records – particular Customers in this case – to users who aren’t the designated owners. This is achieved through many and varied mechanisms. For example, by default the role hierarchy in Salesforce grants access through sharing. If Eve is configured to be in a role above Adam then she automatically gains access to Customers he has created.
Through our Salesforce assessments[2], we have seen many real-life examples of how sharing can be misconfigured. For example, a financial services client had configured their own login page to a new customer portal, which we were testing before go-live. During our review we discovered that the login process was entirely custom and did not rely on Salesforce’s own authentication mechanism. The Salesforce account under which context the site’s code was running necessarily required access to all customer records. As far as Salesforce was concerned, however, this code executed under that same account whether or not a customer was logged in. Not only did this shift the onus on the custom code to perform all the authorisation logic, which was also found to be flawed, but other ‘native’ Salesforce calls could be made that allowed personally identifiable information (PII) to be extracted unauthenticated.
Raccoon can help to highlight sharing misconfigurations from the starting point of “this is the data I care about”. You supply a list of objects – typically those containing sensitive data – and it will enumerate the Profiles and Permissions Sets that have some combination of read/edit/delete permissions to all records for those objects. But what is sensitive data? The answer varies between organisations, of course, but it invariably includes personal information about people. At this point, it’s worth mentioning a second real-life case, as it illustrates why this view is not definitive. A client that had integrated a popular enterprise call centre solution with Salesforce had misconfigured sharing relating to a configuration object. This effectively allowed a standard call centre user to edit a record that had functional significance to the entire organisation.
A privileged Salesforce user with access to Setup can use Sharing Settings and the Portal Health Check to gain an overview of sharing, but this view is somewhat limited. For example, the Sharing Overrides listed for an object under Sharing Settings does not consider Permission Sets, which is a common – and, in fact, recommended – way to extend user privileges. Other aspects about the effective sharing are missing from these views. The Organization-wide default (OWD) for the Customer object could be configured as ‘Public Read/Write’, but without the complementary permissions on the Customer object itself, access will be denied. For example, Isa, who does not have ‘read’ permission on the Customer object, cannot view any Customer record despite the relaxed default sharing model. But even if Isa had read/edit/delete permissions on the Customer object, it’s notable that an OWD of ‘Public Read/Write’ does not confer the delete privilege on shared records. Unless, that is, the Customer sharing model was ‘Controlled by Parent’ and the parent’s OWD was ‘Public Read/Write’. In this ‘Master-Detail’ relationship, delete on the child record would be granted.[3] But this isn’t true for certain special standard relationships, such as between Account and Contact. The sharing model for Contact can be set to ‘Controlled by Parent’ but it doesn’t quite follow all the rules of a Master-Detail relationship. Indeed, the Account field on the Contact object is actually of type ‘Lookup’ (as opposed to ‘Master-Detail’) which usually doesn’t offer sharing to be ‘Controlled by Parent’. Raccoon considers the slight deviations in behaviour for special children of Account. The devil is in the detail.
We should also pause to remember that the OWD is just a default: it can be overridden. Permissions can be applied via Profiles or Permission Sets which allow assigned users to ‘view all’ or ‘modify all’ records for a particular object (‘modify’ here includes delete). There is also the wider ‘view all data’ and ‘modify all data’ permission, which gives wholesale access to all records for all objects.
It’s evident from the discussion so far that the Salesforce sharing model is indeed a “complex relationship”. And yet this account is far from complete. Small wonder, then, that organisations can lose control of who has access to what, especially over time. Because of the complexity of sharing, Raccoon focuses on configurations that allow access to all records for the objects supplied. It doesn’t consider isolated instances of sharing such as those configured by users on individual records. It’s important to review the README to understand exactly what Raccoon does and doesn’t consider. And, like any tool, it cannot take into account legitimate business reasons for relaxing access (for example, an integration account, although these too are often over-privileged). Nevertheless, Raccoon aims to help with gaining and maintaining assurance in Salesforce deployments by identifying excessive access for which there is no or insufficient business justification.
Jerome Smith @exploresecurity
[1] https://help.salesforce.com/articleView?id=sf.security_sharing_considerations.htm&type=5
[2] https://research.nccgroup.com/2020/06/02/common-insecure-practices-with-configuring-and-extending-salesforce/
[3] An OWD of even ‘Public Read Only’ on the parent can confer both edit and delete on child records (again, so long as the object permissions match) when the relevant field’s Master-Detail Options > Sharing Setting is set to “Read Only: Allows users with at least Read access to the Master record to create, edit, or delete related Detail records”.