<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Chris Feldhacker on Medium]]></title>
        <description><![CDATA[Stories by Chris Feldhacker on Medium]]></description>
        <link>https://medium.com/@feldhacker.chris?source=rss-3c1f555a87ab------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*p3vrdtkBlg2JXvmejJSTZg.jpeg</url>
            <title>Stories by Chris Feldhacker on Medium</title>
            <link>https://medium.com/@feldhacker.chris?source=rss-3c1f555a87ab------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 12:22:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@feldhacker.chris/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Restrict Guest User Access to the GraphQL API for Salesforce Orgs]]></title>
            <link>https://medium.com/@feldhacker.chris/restrict-guest-user-access-to-the-graphql-api-for-salesforce-orgs-e27dc9f6b3bc?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/e27dc9f6b3bc</guid>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-admin]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 13 Aug 2026 15:38:53 GMT</pubDate>
            <atom:updated>2026-09-18T15:06:37.439Z</atom:updated>
            <content:encoded><![CDATA[<p>Enable this important security setting to close the door on an attack vector that has become a favorite for threat actors.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jk7TWvefJUSIcKmqN8l46g.png" /></figure><p>Salesforce has updated the <a href="https://help.salesforce.com/s/articleView?id=release-notes.salesforce_release_notes.htm&amp;release=264&amp;type=5">Winter 27 Release Notes</a> with this important security update related to the GraphQL API:</p><blockquote>“Added a release note to announce that admins can control guest user access to GraphQL API.”</blockquote><p>The <a href="https://help.salesforce.com/s/articleView?id=release-notes.rn_api_graphql.htm&amp;release=264&amp;type=5">Graph API changes page</a> provides more details:</p><blockquote><strong>Control unauthenticated guest user access to GraphQL API for your org</strong></blockquote><blockquote>Guest user access is off by default in new orgs and in orgs that haven’t had guest user GraphQL access since February 2026. For existing orgs with guest user GraphQL access since February 2026, guest user access is enabled so that there aren’t any changes to current behavior. Admins can change guest user access to GraphQL from Setup. In the Quick Find box, enter API Access Controls and select it, and then update guest user access.</blockquote><blockquote>In orgs with guest user access turned off, guest users can’t access the GraphQL API endpoint and receive an error when making requests. In orgs with guest user access turned on, GraphQL API honors the same object-level and field-level permissions that guest users have in the org.</blockquote><p>According to the changes noted in the <a href="https://help.salesforce.com/s/articleView?id=release-notes.rn_api_meta.htm&amp;release=264&amp;type=5">Metadata API</a>:</p><blockquote>Use the new enableGraphQLApiGuestUserAccess field on the existing SecuritySettings metadata type to update guest user access to GraphQL API.</blockquote><h3>Implications</h3><p>This security improvement is huge!</p><p>Threat actors have taken advantage of guest user access through the GraphQL API over the past several months to extract information that has been unintentionally exposed to guest users, or to access information that wasn’t accessible via other APIs.</p><p>Restricting guest user access to the GraphQL API slams shut a very large doorway into Salesforce orgs. Ensuring this security setting is enabled should be treated as a “critical” security risk finding.</p><h3>Take Action!</h3><p>Owners of existing Salesforce orgs should enable the setting under “Setup &gt; Security &gt; API Access Controls” as soon as it become available within your org. Salesforce announced this change with the Winter 27 release, and rollout to production orgs happens September 4 — October 9. <a href="https://admin.salesforce.com/blog/2026/admin-winter-27-release-countdown">Check the schedule for your org</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MXvNJAVfD1QPE_c2HnNYiw.png" /></figure><p><em>Note: If your org previously contacted support to enable API Access Control in the past, Setup will have both a “API Access Control” (old) and “API Access Control</em><strong><em>s</em></strong><em>” (new) pages available. Double-check which page you are on.</em></p><h3>Impacts</h3><p>For many Salesforce orgs, enabling this security setting is expected to be completely transparent and have no functional impact. Salesforce orgs that have deployed customizations to deliberately take advantage of guest user access to the GraphQL APIs would require deeper analysis and need to assess the risk-benefit trade-offs of continuing to expose the GraphQL APIs to guest users.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e27dc9f6b3bc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Retrieving Salesforce External Client App OAuth Keys and Secrets in Bulk]]></title>
            <link>https://medium.com/@feldhacker.chris/retrieving-salesforce-external-client-app-oauth-keys-and-secrets-in-bulk-10e68af08acc?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/10e68af08acc</guid>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-productivity]]></category>
            <category><![CDATA[salesforce-admin]]></category>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 19 Feb 2026 22:25:38 GMT</pubDate>
            <atom:updated>2026-07-06T13:49:02.200Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TbI9mazDi3DBGuZT" /><figcaption>Photo by <a href="https://unsplash.com/@andreicastanha?utm_source=medium&amp;utm_medium=referral">Andrei Castanha</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>You find yourself with a Salesforce sandbox loaded with “Local” External Client Apps (ECAs), many of them OAuth-enabled.</p><p>Your goal is to obtain the Consumer Key and Secrets for all of the ECAs, in order to update client applications with connection information.</p><p>The reasons <em>why </em>this scenario arises are varied, and exactly <em>how </em>Local ECAs were created <em>en masse</em> in a sandbox is an exercise that each customer gets the privilege to solve.</p><p>But here you are.</p><p>Gathering consumer keys and secrets individually can be time consuming, involves a lot of clicking, throw-backs into Classic mode, and maybe even an access code for fun!</p><p>Salesforce does provide a means to retrieve OAuth secrets via Metadata API, but Salesforce Support must be contacted to enable this feature, and it’s unclear how long this setting might remain an option. Salesforce discourages customers from using the Metadata API to retrieve OAuth secrets as doing so carries the risk that secrets might inadvertently be retrieved along with other metadata information and stored somewhere insecure, such as being committed to a version control repository. To reduce this risk, Salesforce provides a means to obtain OAuth secrets using the REST API instead.</p><blockquote>Retrieving OAuth secrets in bulk should only be performed against a sandbox; retrieving OAuth secrets in bulk against a production org would be unwise.</blockquote><h3>The Walkthrough</h3><p>First, there’s an org setting that must be enabled:<br>Setup &gt; Apps &gt; External Client Apps &gt; Settings &gt; “Allow access to External Client App consumer secrets via REST API”.</p><p>This setting is currently undocumented and the exact system permissions needed are unknown, but trust me its there. (Users in the System Administrator profile will have no problem.) This setting can be enabled without contacting support.</p><blockquote>Security Tip: Leave this setting enabled only as long as necessary. If retrieving secrets via REST API is a one-time occurrence, you should really consider disabling this setting after the task is complete in the spirit of minimizing your attack surface, even if it is just a sandbox.</blockquote><p>Next, we need to understand the REST endpoint involved, which is labeled “<a href="https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_oauth_credentials_resources.htm">OAuth Credentials Resources</a>”.</p><p>The full REST URL that ultimately needs to be called looks something like this:</p><pre>/services/data/v{LATEST}/apps/oauth/credentials/{ECA_ID}/{CONSUMER_ID}?part=keyandsecret</pre><p>And here’s an example:</p><pre>/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC?part=keyandsecret</pre><p>To break it down:</p><ol><li>Use the latest API version</li><li>The ECA_ID (0xI) is the Id of the record from the “ExternalClientApplication” object, which is accessible to customers.</li><li>The CONSUMER_ID (888) is the Id of an object called “OauthConsumer”, which is a behind-the-scenes object NOT accessible to customers.</li></ol><p>If “OauthConsumer” is a hidden object, how do you get the Ids needed?</p><p>Well, it is actually necessary to make <em>two</em> REST requests: the initial request will provide the key and information about the OauthConsumer(s) present (Local ECAs should only have one), and another request is required to retrieve the secret. Technically, the key is available in both the first and second request, so where you want to grab it from is up to you!</p><p>Example first GET request looks like:</p><pre>/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123</pre><p>Example first response:</p><pre>{<br>  &quot;consumers&quot; : [ {<br>    &quot;id&quot; : &quot;888WD0000009fK0ABC&quot;,<br>    &quot;key&quot; : &quot;3MVABCD9prPrtlptGtV4B0J4hi7VbpxK0c7&quot;,<br>    &quot;name&quot; : &quot;ExampleConnectedApp&quot;,<br>    &quot;url&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC&quot;<br>  } ],<br>  &quot;currentPageUrl&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123&quot;<br>}</pre><p>Example second GET request looks like:</p><pre>/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC?part=keyandsecret</pre><p>Example second response:</p><pre>{<br>  &quot;id&quot; : &quot;888WD0000009fK0ABC&quot;,<br>  &quot;key&quot; : &quot;3MVABCD9prPrtlptGtV4B0J4hi7VbpxK0c7&quot;,<br>  &quot;name&quot; : &quot;ExampleConnectedApp&quot;,<br>  &quot;secret&quot; : &quot;9F1321654BCA987E7ABD6C5A782AC25F2E6&quot;,<br>  &quot;url&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC?part=keyandsecret&quot;<br>}</pre><p>Repeat these REST GET requests for each Local ExternalClientApplication in the org and you’ve collected all the keys and secrets!</p><p><strong>Note</strong>: Only ECAs that are OAuth-enabled will have an OAuth key and secret, but determining which ECAs are OAuth-enabled is more complicated as this is not a attribute available in the ExternalClientApplication table. If an ECA is not OAuth-enabled, the REST endpoint can still be called but the list of consumers is empty; the response looks like this:</p><pre>{<br>  &quot;consumers&quot; : [ ]<br>}</pre><blockquote>Remember, OAuth secrets are considered sensitive information and should be handled according to the policies at your company.</blockquote><h3>The Solution</h3><p>Rather than posting a script or link to a GitHub repo, I’m going to encourage you to solve this problem using AI! (Hands-on exercise!)<br>Just share with AI the goal, what output we want, and the specifics of what we DO know and let AI generate the solution for us!</p><p>Here is an real AI prompt to generate a PowerShell script you can give to Copilot or your favorite AI tool and try it out! (No IDE required!)</p><pre>Create a stand-alone Powershell script named Retrieve-EcaSecrets.ps1 that will gather External Client App (ECA) OAuth consumer keys and secrets. Accept a Salesforce CLI org alias as required input. Assume Powershell v5+, favor using built-in operators and cmdlets over .NET types.<br><br>Perform the following steps to gather ECA general information:<br>Use the Salesforce CLI (using sf commands, not sfdx) to execute the following SOQL query, returning JSON format: <br>SELECT Id,DeveloperName FROM ExternalClientApplication WHERE DistributionState = &#39;Local&#39; <br><br>DeveloperName is the ECA name.<br>Use the Salesforce CLI &quot;org display&quot; command to retrieve org information (InstanceUrl, ApiVersion), the &quot;org auth show-access-token&quot; command to obtain the access token, but then use the PowerShell &quot;Invoke-RestMethod&quot; function to call Salesforce REST APIs.<br><br>For each ECA Id returned from the SOQL query, perform a sequence of 2 REST GET requests: <br>First url: &quot;$InstanceUrl/services/data/v$ApiVersion/apps/oauth/credentials/{ECA_ID}&quot; <br><br>The expected response is like:<br>```<br>{<br>  &quot;consumers&quot; : [ {<br>    &quot;id&quot; : &quot;888WD0000009fK0ABC&quot;,<br>    &quot;key&quot; : &quot;3MVABCD9prPrtlptGtV4B0J4hi7VbpxK0c7&quot;,<br>    &quot;name&quot; : &quot;ExampleConnectedApp&quot;,<br>    &quot;url&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC&quot;<br>  } ],<br>  &quot;currentPageUrl&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123&quot;<br>}<br>```<br>From the first &quot;consumer&quot; object returned, the &quot;url&quot; property contains the url to be used for the second GET request.<br>Second url: &quot;$InstanceUrl$CONSUMER_URL?part=keyandsecret&quot;<br>The expected response is like:<br>```<br>{<br>  &quot;id&quot; : &quot;888WD0000009fK0ABC&quot;,<br>  &quot;key&quot; : &quot;3MVABCD9prPrtlptGtV4B0J4hi7VbpxK0c7&quot;,<br>  &quot;name&quot; : &quot;ExampleConnectedApp&quot;,<br>  &quot;secret&quot; : &quot;9F1321654BCA987E7ABD6C5A782AC25F2E6&quot;,<br>  &quot;url&quot; : &quot;/services/data/v64.0/apps/oauth/credentials/0xIWD0000001ZIZ123/888WD0000009fK0ABC?part=keyandsecret&quot;<br>}<br>```<br>For each ECA record, save the ECA name from the SOQL query along with the &quot;key&quot; and &quot;secret&quot; from the REST response.<br>Display final results like:<br>```<br>ECA Name 1<br>key: (key)<br>secret: (secret)<br><br>ECA Name 2<br>key: (key)<br>secret: (secret)<br>```<br>Allow the user to optionally save the output to a file, support both JSON and CSV formats.</pre><p>The result will be a 200–300 line Powershell script, with comments at the top of the script providing examples of how to use it. Save the script to a file named “Retrieve-EcaSecrets.ps1”. The assumption is that you have the latest Salesforce CLI installed, and you’ve logged in using the CLI and created an “OrgAlias” to the sandbox you are targetting.</p><p>Review the script, tweak if needed (I didn’t need to), and try it out!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10e68af08acc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why OAuth Device Flow is a Security Risk to Salesforce Orgs]]></title>
            <link>https://medium.com/@feldhacker.chris/why-oauth-device-flow-is-a-security-risk-to-salesforce-orgs-7f02244b1896?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/7f02244b1896</guid>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-admin]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-developer]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 21 Aug 2025 02:01:47 GMT</pubDate>
            <atom:updated>2025-08-29T16:05:31.435Z</atom:updated>
            <content:encoded><![CDATA[<p>Not all security standards are appropriate for all applications.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2EEq1j3m_rjazHJ7" /><figcaption>Photo by <a href="https://unsplash.com/@markuswinkler?utm_source=medium&amp;utm_medium=referral">Markus Winkler</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In a previous article, I provided <a href="https://medium.com/@feldhacker.chris/protect-against-the-salesforce-data-loader-related-security-threats-ababb90e161d">steps Salesforce org owners needed to perform in order to protect Salesforce orgs against the ongoing security threat</a>. Salesforce’s “allow by default” approach to integrations was identified as a contributing factor, as was the OAuth Device Flow support by Data Loader. This article will dive a bit deeper and explain why OAuth Device Flow is not risk-appropriate for many Salesforce orgs.</p><blockquote>Salesforce has also recognized these gaps and will be acting soon to close them. See <a href="https://help.salesforce.com/s/articleView?id=005132365&amp;type=1">Prepare for Connected App Usage Restrictions Change</a> and <a href="https://help.salesforce.com/s/articleView?id=005132367&amp;type=1">Data Loader OAuth 2.0 Device Flow Removal</a>. Yay, security improvements!</blockquote><p>But if OAuth Device Flow is a recognized “standard”, what makes it so risky to use in a Salesforce org?</p><h3>Your Salesforce Org Requires More Protection Than Netflix on Your TV</h3><p>The details of how the OAuth Device Flow works on Salesforce is <a href="https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_device_flow.htm&amp;type=5">documented on this page</a>. What’s easy to overlook in the steps is that different devices are involved, with different steps taking place on different devices.</p><p>It’s easiest to explain through a demonstration. (You can even follow along if Salesforce improvements have not yet gone live by the time you read this!)</p><p>First, open up Data Loader, choose an operation (say, “Export”), choose “OAuth”, choose an Environment, and click “Log in”.</p><p>Two things will happen: 1) Data Loader will display a device code along with a convenient URL for you to copy, and 2) a web browser will pop open to the URL:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/769/1*sjKhudbUNr36gzQeLsbQPg.png" /><figcaption>The device code and URL displayed within Data Loader.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/627/1*JxtNDO8do25Tk5AGg8_mZA.png" /><figcaption>The web browser popped open to the URL with the device code prepopulated.</figcaption></figure><p>In this typical scenario, both Data Loader and the web browser are running on the same device — you click “Connect”, login (if not already), and Data Loader establishes a connection. This scenario is boring and doesn’t demonstrate the problem at all.</p><p>Let’s make things more interesting.</p><p>Instead of clicking “Connect” in your browser, copy the URL from Data Loader with the device code and send it to your coworker who also has Salesforce access. (<em>With their full knowledge and consent of this demonstration, of course!</em>) The demonstration is even more slick if the coworker has also used Data Loader in the past.</p><p>If you want to make it fancy, send the URL through a URL-shortener first to add a bit of mystery.</p><p>Coax your coworker into clicking on the link, logging in to Salesforce like normal, and the same window appears:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/627/1*JxtNDO8do25Tk5AGg8_mZA.png" /><figcaption>Pro tip: if you setup the My Domain URL in Data Loader instead of the generic Salesforce URL, your company logo will even appear!</figcaption></figure><p>After instructing them to click “Connect”, the following screen <em>may </em>appear (if the coworker has never used Data Loader before):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*AaVONA40gmdzbq3kqGNXMg.png" /></figure><p>Instruct them to click “Allow”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/601/1*UIqUVhL0cU_aTm3f9oxqjA.png" /><figcaption>Again, company logo may appear if My Domain was used.</figcaption></figure><p>Finally, click “Continue”. The coworker can close the web browser on their device.</p><p>Back on your device, and assuming the end-to-end process didn’t take an excessive amount of time, Data Loader is now connected!</p><p>The end result: Data Loader is running on your device connected to Salesforce and operating with the permissions of your coworker!</p><p>Is that it? What’s the big deal?</p><h3>Some Highlights of What Just Happened</h3><p>You (playing the role of a threat actor) executed Data Loader from any device of your choosing.</p><p>Your coworker (playing the role of a victim) did not need to reveal any sensitive information or secrets.</p><p>Your coworker did not need to be tricked into downloading or installing any software.</p><p>Your coworker may have seen familiar URLs and company logos throughout the process.</p><p>You did not need to modify or use a “malicious” version of Data Loader, you used Data Loader out-of-the-box.</p><p>The shortest possible attack chain involves three steps:</p><ol><li>User clicks on a URL to the Salesforce device code page with the threat actor’s device code pre-populated (if not already logged in, user logs-in to Salesforce like normal)</li><li>User clicks “Connect”</li><li>User clicks “Continue”</li></ol><h3>Ineffective Security Controls</h3><p>Let’s dive deeper into why OAuth Device Flow poses such a concern.</p><p>Data Loader is running on Device A under the threat actor’s control, and the coworker is running on Device B just “logging in to Salesforce like normal”. Therein lies the problem.</p><p>When the coworker “logged in to Salesforce like normal”, many companies have a variety of security controls in place intended to provide increased application security.</p><p>Username and passwords provide the most basic protection, but the user’s credentials did not need to be stolen, phishing, or otherwise revealed.</p><p>MFA (which is required in all Salesforce orgs) did not provide any protection against this scenario, and the user did not have to disclose an MFA code to the threat actor. The user didn’t have to reveal <em>any</em> information at all!</p><p>If the company utilizes SSO, SSO provided no protection, and SSO with MFA provided no protection. Even an SSO solution with fancy conditional access policies like enforcing certain IP ranges, maybe throwing up extra security questions, or even performing device-level checks to verify certain management or other company-required software is installed — <em>none of it matters</em>. Remember, all of these checks are happening to the victim on Device B, not Device A being used by the threat actor. And the victim passes all the checks with flying colors! The victim is, after all, a legit user.</p><p>Even if the company required X.509 certificates for authentication that still wouldn’t be enough.</p><p>Socially engineer a user to click a link and a couple buttons, and game over.</p><h3>Working As Designed</h3><p>The OAuth Device Flow is designed to work this way on purpose. Logging in to your favorite streaming service on your TV might be cumbersome and a poor user experience. So just pull out your phone, navigate to this URL, login, and enter this special code and you’re in (meaning, the application running <em>on your TV</em> is granted access). Or, to make it even easier, here’s a QR code to scan.</p><p>The next time your TV displays a code for access to a streaming service, call up your friend, convince <em>them</em> to login to their account and enter the code you give them, and now your TV will be connected under <em>your friend’s</em> account. A similar outcome as demonstrated above is achieved.</p><p>However, the stakes are <em>a lot higher</em> if an unauthorized connection is made to your Salesforce org than if your favorite streaming service is compromised. If your Salesforce org is only storing grandma’s favorite recipes you might not be too concerned; but if your Salesforce org is storing loads of customer, business, and financial data, staying far away from OAuth Device Flow might be prudent.</p><h3>In the Real World</h3><p>Threat actors in the real world might find it hard to convince users to authorize a connection with the label “Dataloader Bulk”, especially if users might be vaguely familiar with the common tool name. So with a little more work, it’s possible for threat actors to come up with a more crafty display name (say, “My Ticket Portal”) that makes convincing users to click an “Allow” button a little easier. But, doing so also requires users to perform a few extra steps.</p><h3>Effective Security Controls</h3><p>I provided recommendations for security controls that do offer effective protection against the current threat against Salesforce orgs in the article <a href="https://medium.com/@feldhacker.chris/protect-against-the-salesforce-data-loader-related-security-threats-ababb90e161d">Protect Against the Salesforce Data Loader Related Security Threats</a>. The protections boil down to 1) Implement API Access Control and 2) Start using only secure connections with Data Loader and block the old Connected Apps that supported OAuth Device Flow. Fortunately, Salesforce will soon be making additional security improvements in both these categories to the core platform. See <a href="https://help.salesforce.com/s/articleView?id=005132365&amp;type=1">Prepare for Connected App Usage Restrictions Change</a> and <a href="https://help.salesforce.com/s/articleView?id=005132367&amp;type=1">Data Loader OAuth 2.0 Device Flow Removal</a>.</p><p>Side note: I mention above that IP restrictions <em>enforced by an SSO provider</em> are ineffective. But Login IP ranges set at the profile level <em>would</em> be effective…<em>if</em> IP restrictions are enforced at every request, and <em>if</em> IP restrictions are enforced at the Connected Application, and <em>if</em> IP restrictions do not interfere with all other integrations used by users in the same profile. In today’s world of remote workers and SaaS integrations, Login IP ranges may not be feasible in some companies.</p><h3>Encourage Salesforce to Do More</h3><p>We know Data Loader supports OAuth Device Flow, but are there others? Wouldn’t it be great if Salesforce just provided a setting to block OAuth Device Flow org-wide, as they currently do for OAuth Username-Password Flow and OAuth User-Agent Flow?</p><p>Please vote for the idea: <a href="https://ideas.salesforce.com/s/idea/a0BHp000016KznlMAC/provide-ability-to-disable-oauth-device-flow">Provide ability to disable OAuth Device Flow</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7f02244b1896" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Protect Against the Salesforce Data Loader Related Security Threats]]></title>
            <link>https://medium.com/@feldhacker.chris/protect-against-the-salesforce-data-loader-related-security-threats-ababb90e161d?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/ababb90e161d</guid>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-admin]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Fri, 08 Aug 2025 21:09:25 GMT</pubDate>
            <atom:updated>2025-10-07T20:40:58.050Z</atom:updated>
            <content:encoded><![CDATA[<p>Specific actions that provide effective protection to Salesforce orgs</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9gBJtXD0fkyJHW3u" /><figcaption>Photo by <a href="https://unsplash.com/@jccards?utm_source=medium&amp;utm_medium=referral">Marek Studzinski</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Background</h3><p>In 2025 threat actors have been targeting Salesforce orgs with social engineering tactics that take advantage of two main security risks: Salesforce’s “allow by default” behavior when it comes to third-party integrations, and less secure authorization mechanisms supported by the Data Loader tool.</p><p>A focal point of the threat is Data Loader’s support for OAuth Device Flow. Although OAuth Device Flow is a standard and has appropriate usage, using OAuth Device Flow with many Salesforce orgs, often containing customer and company data, is not risk-appropriate.</p><p>As a result, deliberate action is needed to effectively protect against the ongoing social engineering threat against Salesforce orgs.</p><blockquote>Diving into the details regarding “why” is a topic for <a href="https://medium.com/@feldhacker.chris/why-oauth-device-flow-is-a-security-risk-to-salesforce-orgs-7f02244b1896">a different article</a>. This article is focused on getting recommendations out there that can make a meaningful difference.</blockquote><h3>Recommendations</h3><p>The outcomes that need to be achieved boil down to two main goals:</p><ol><li>Prevent users from utilizing unapproved tools and integrations (Connected Applications)</li><li>Prevent users from utilizing the OAuth Device Flow with Data Loader</li></ol><p>Both outcomes need to be achieved to provide effective protection.</p><h3>1. Prevent Unapproved Tools and Integrations</h3><p>The <a href="https://medium.com/@feldhacker.chris/enabling-salesforce-api-access-control-7a45254a42e4">Enabling Salesforce API Access Control</a> article provides instructions and a recommended approach for enabling a feature that switches Salesforce orgs from an “allow by default” approach to a more secure “deny by default” model.</p><p>However, the “API Access Control” feature is not ironclad. Due to certain limitations, many orgs owners that implement this feature will realize that some gaps still remain. This is due to the fact that in order to maintain functionality a subset of users will need to be assigned a special permission called “Use Any API Client”, which not only switches those users back into the “allow by default” mode, but those users are also permitted to use Connected Apps that have been deliberately blocked!</p><p>The number of users assigned this permission should be limited and closely governed. Some orgs may find this easier said than done.</p><p>Embracing the “deny by default” model is still an important and effective accomplishment, and org owners will have improved visibility into exactly where risk remains.</p><blockquote>Update: In September 2025 Salesforce made platform-wide changes to <a href="https://help.salesforce.com/s/articleView?id=005132365&amp;type=1">embrace the “deny by default” model</a> without the need for the “Use Any API Client” permission. Readers should still perform the steps in the <a href="https://medium.com/@feldhacker.chris/enabling-salesforce-api-access-control-7a45254a42e4">Enabling Salesforce API Access Control</a> article to install and review Connected Apps to ensure each one is set to “Admin approved users are pre-authorized”.</blockquote><h3>2. Prevent Data Loader OAuth Device Flow Usage</h3><p>Complicating the situation are a number of key points:</p><ol><li>The “Dataloader Bulk” and “Dataloader Partner” Connected Apps are installed as part of a managed package named “Salesforce Connected Apps”.</li><li>The managed package includes several Connected Apps bundled together, including:<br>Dataloader_Partner<br>Dataloader_Bulk<br>Forcecom_Migration_Tool<br>Forcecom_IDE<br>Salesforce_Touch<br>Salesforce_Mobile_Dashboards<br>Workbench<br>Salesforce_for_Outlook</li><li>Connected Apps in a managed package cannot have their OAuth settings, nor IP restrictions, modified by subscriber owners (customers).</li></ol><p>As a result, Data Loader cannot be independently uninstalled as many orgs also utilize at least one other tool included in the package, and the managed Connected Apps cannot be modified in a meaningful way.</p><p>To achieve the desired outcome, the strategy being advocated below is to “stop using the old, start using the new”.</p><h3>Out With the Old — Restrict</h3><p>If org owners conclude that uninstalling the “Salesforce Connected Apps” package is not feasible, user access to the older Data Loader Connected Apps must be controlled.</p><p>Access to the legacy “Dataloader Bulk” and “Dataloader Partner” Connected Apps should be removed from all Profiles and Permission Sets. As long as “API Access Control” has been fully implemented as recommended previously, removing user access from the Connected Apps will be effective at preventing users from being tricked into inadvertently authorizing a threat actor using these out-of-the-box apps. The users that would remain at-risk would be the users that were assigned the “Use Any API Client” permission.</p><h3>Out With the Old — Block</h3><p>Want to close the door on the Data Loader Connected Apps even more?</p><blockquote>This option is only available to orgs with Salesforce Shield or an Event Monitoring addon subscription.</blockquote><p>Salesforce Shield provides a Transaction Security Policy (TSP) feature that allows more fine-grained control over certain user activities within an org. Fortunately, preventing the older Data Loader Connected Apps from being used is one such activity that can be prevented by creating a TSP.</p><p>In Salesforce Setup under “Transaction Security Policies”, a new TSP can be created using Condition Builder (no Apex needed!) on the LoginEvent with the following conditions:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dg2NYkFJVfGqKp-N6H90xA.png" /><figcaption>Important: The “OR” condition must be used with each value</figcaption></figure><p>The values specified are the names of the Data Loader Connected Apps, as well as some additional values identified by Salesforce. (See: <a href="https://help.salesforce.com/s/articleView?id=000387715&amp;type=1">Data Loader Application Values</a>)</p><p>In the Actions section, choose “Block” as the Action, and select a notification option, if desired. The TSP can also be enabled now, or enabled / disabled later from the main list.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1-tuRLJdta0yjk7A8vzDJQ.png" /><figcaption>A Recipient is required even if no Notification options are selected.</figcaption></figure><p>The great advantage with having a blocking TSP in place is that the TSP takes precedence over the “Use Any API Client” permission. Meaning, if org owners found it necessary to assign the “Use Any API Client” permission to some users, those users are now also protected against the current security threat. (Well, at least in a scenario where the threat actor choose <em>not </em>to customize the application name.)</p><p>If users attempt to authenticate via OAuth to the Data Loader Connected Apps, login history for the user will show a Status of “Failed: Blocked by security policy”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/668/1*1y9eCyxVm4uqu1PG8gTAkA.png" /><figcaption>Note that Salesforce reports the Login Subtype as “OAuth Web Server” even through the actual type should be something like “OAuth Device”. Why Salesforce is misreporting the type is unknown.</figcaption></figure><p>It is also worth mentioning that the Data Loader client itself may not be fully blocked, as some authentication mechanisms report an Application of “N/A” with the LoginType “Other Apex API”. This combination of LoginEvent values is not unique to Data Loader but will appear with other client types as well in certain scenarios when non-OAuth authentication mechanisms are used.</p><p>Nonetheless, the main outcome is achieved — preventing Data Loader OAuth Device Flow usage, which is the mechanism threat actors are taking advantage of through social engineering. Stealing credentials and logging in to application directly is a different problem, and is a risk that extends beyond just Salesforce Data Loader.</p><p>So what’s a better alternative to using the legacy Data Loader Connected Apps?</p><h3>In With the New</h3><p>Fortunately, starting with the v64.0.2 release, Data Loader now supports a more secure connection mechanism using an External Client App (ECA), which is a new and still maturing metadata type intended to replace Connected Apps in the near future. As of this writing, the Data Loader ECA is not delivered via managed package, instead org owners must create their own ECA for Data Loader within each org. This gives customers full control over the configuration of the ECA. For details, see:</p><p><a href="https://developer.salesforce.com/docs/atlas.en-us.dataLoader.meta/dataLoader/loader_eca_oauth_pkce.htm">Create a Secure Connection with an External Client App</a></p><p>The Data Loader ECA should be configured to only support the OAuth Web Server flow with PKCE.</p><p>Once in place, users should only utilize the secure Data Loader connection using the ECA moving forward.</p><blockquote>ECAs that are not packaged are referred to as “Local” ECAs. Unlike Connected Apps or packaged ECA, when a sandbox is created Local ECAs are not automatically copied down (as of the Summer 25 release). This has implications customers need to think through.</blockquote><blockquote>Update: In September 2025 Salesforce <a href="https://help.salesforce.com/s/articleView?id=005132367&amp;type=1">announced global changes to Data Loader to disable the use of OAuth Device Flow</a>, and to only use more secure OAuth flows in v64.1.0+. With the improvements in place, it is no longer necessary to implement the External Client App approach, nor to implement a Transaction Security Policy as described above.</blockquote><h3>Summary</h3><p>Although security will never be perfect and the risk is never zero, implementing the recommendations above should be effective at countering the going threat against Salesforce orgs and reducing the risk to more appropriate levels for many org owners.</p><h3>Have a minute? Please go vote for:</h3><ul><li><a href="https://ideas.salesforce.com/s/idea/a0B8W00000Gdq50UAB/developer-console-not-fully-consistent-with-salesforce-api-access">Developer Console not fully consistent with Salesforce API access</a></li><li><a href="https://ideas.salesforce.com/s/idea/a0B8W00000QcGF5UAN/provide-a-permission-to-control-access-to-apis-that-dont-use-a-connected-app">Provide a permission to control access to APIs that don’t use a connected app</a></li><li><a href="https://ideas.salesforce.com/s/idea/a0BHp000016KznlMAC/provide-ability-to-disable-oauth-device-flow">Provide ability to disable OAuth Device Flow</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ababb90e161d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enabling Salesforce API Access Control]]></title>
            <link>https://medium.com/@feldhacker.chris/enabling-salesforce-api-access-control-7a45254a42e4?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a45254a42e4</guid>
            <category><![CDATA[salesforce-admin]]></category>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 07 Aug 2025 00:12:30 GMT</pubDate>
            <atom:updated>2025-10-07T20:46:35.807Z</atom:updated>
            <content:encoded><![CDATA[<p>Practical guidance to improve org security in a meaningful way through incremental steps.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ukBW-HizWh6o3pUr" /><figcaption>Photo by <a href="https://unsplash.com/@partial_exposure?utm_source=medium&amp;utm_medium=referral">Joe Pee</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Overview</h3><p>When it comes to third-party integrations, Salesforce orgs have an “allow by default” security model. Salesforce end users are empowered to discover and implement third-party integrations at-will, and the third-party service provider is granted access to the same data and can perform the same actions as the end user, often with just the click of a button. Allowing unvetted and arbitrary service providers access to Salesforce org data is not risk-appropriate in many situations, especially for orgs containing sensitive customer and company information. Deliberate action is required to configure orgs to use a “deny by default” security model.</p><p>Salesforce provides an “<a href="https://help.salesforce.com/s/articleView?id=xcloud.security_api_access_control_about.htm&amp;type=5">API Access Control</a>” feature that allows third-party integrations to be controlled, removing the ability for regular end users to grant access to arbitrary integrations, and instead require integrations to be expressly authorized by Salesforce administrators.</p><p><em>Enabling “API Access Control” within an org can be impactful and disruptive if not implemented carefully.</em> The instructions provided below go beyond what is provided by Salesforce documentation and include recommendations intended to minimize impacts, divide the work into more manageable chunks, and ease the process overall.</p><h3>Key Points</h3><ul><li>API Access Control is an org-wide setting. Once enabled, users will only be able to access Connected Applications to which the users have been granted explicit access to use. Users are granted access to Connected Applications either via Permission Sets (recommended) or at the Profile level (considered divest).</li><li>If permission to use a given Connected Application is not put into place <em>before</em> API Access Control is enabled, then users will suddenly lose access to the Connected Application. <em>Proper preparation is critical to prevent scrambling to resolve sudden issues that may surface when API Access Control is fully enabled.</em></li><li>In order to grant access to a Connected Application, the Connected Application must be “installed”. The “Connected Apps OAuth Usage“ page in Salesforce will show most of the Connected Applications that have been used since the org was created; some will be “installed”, some may not be. By default, Salesforce will permit users to access all Connected Applications, even if they have not been “installed”.</li></ul><blockquote>Update: In September 2025, Salesforce <a href="https://help.salesforce.com/s/articleView?id=005132365&amp;type=1">announced a platform-wide change to embrace the “deny by default” security model across all Salesforce orgs</a>. Org owners should still review and install Connected Apps, and ensure each one is set to “Admin approved users are pre-authorized”. However, the final Step #5 below can now be <strong>skipped</strong>, and the gotchas that come with the “Use Any API Client” permission can now be avoided.</blockquote><h3>Instructions / Recommendations</h3><p>The instructions below involving implementing API Access Control gradually, application-by-application, in order to minimize impacts and avoid overwhelming support staff with any unforeseen issues.</p><blockquote>As always, perform testing to the extent feasible in a sandbox environment first, and follow production change controls appropriate at your company.</blockquote><p>1 Review the applications listed on “<strong>Connected Apps OAuth Usage</strong>“ page in Salesforce setup. Click “Install” next to each application that is (or will be) allowed to be used in the org.</p><ol><li>For applications that are not allowed, click “Block” or “Uninstall”. “Block” will leave the application in the usage list but prevent users from accessing it, which is really just an interim solution until API Access Control is enabled. “Uninstall” will remove the application from appearing in the list, but if any users continue to use the application it will just re-appear.</li><li>Note that installing an application has no operational impact; blocking an application does.</li></ol><p>2 Determine a strategy for managing Connected Applications and granting users access to them. This is an art, not a science.</p><ol><li>In many customer orgs, some Connected Applications are special-purpose, intended to provide company-created integrations access to Salesforce data. These applications are the easiest to prepare, as only the appropriate integration user should be granted access to the Connected Application. It is assumed such integration user to Connected Application permission mappings are already in place, and these applications should typically not be granted to any other user personas.</li><li>For smaller orgs or orgs with few personas, it might be acceptable to manage all Connected Applications with a single Permission Set (new or existing) to which all users have been assigned.</li><li>For orgs with multiple distinctive personas, it might be more appropriate to manage Connected Applications in logical groups using multiple Permission Sets. For example, perhaps some Connected Applications are acceptable to be used by any and all end users, while other Connected Applications might be risk-appropriate to be used only by users in, say, an “engineering” persona. It is recommended that each Connected Application should be assessed based on the functionality it provides, the “guardrails” it provides (or lack thereof), and overall risk appropriateness of the application and the personas to which the app is being granted access.</li></ol><p>3 For each Connected Application listed on the “<strong>Manage Connected Apps</strong>” page in Salesforce Setup, perform the procedures below.</p><ol><li>Add the Connected Application to the Permission Set(s) needed for the personas that need access.</li><li>Edit the Connected Application and set the “Permitted Users” value to “<strong>Admin approved users are pre-authorized</strong>”.</li><li>Test and monitor for user feedback.</li><li>Rinse. Repeat. Changes can be deployed to production one application at a time.</li></ol><p>4 At this point, all Connected Applications should be set to “Admin approved users are pre-authorized”, and users are prevented from accessing applications to which the users have not been granted explicitly access — <em>for the Connected Applications that have been installed!</em> However, users are still able to discover and utilize new third-party integrations and services because API Access Control has not been actually enabled yet.</p><p>5 In the “API Access Control” page in Salesforce setup, enable the “<strong>For admin-approved users, limit API access to only allowlisted connected apps</strong>” setting. This is the final step to make API Access Control fully effective.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*q8_CNVIlu_766Jt6d7ECyA.png" /><figcaption><strong>Caution</strong>: Adequate sandbox testing is required before enabling this setting in a production org!</figcaption></figure><p>But wait, there’s more!</p><h3>The No Connected Application Gotcha</h3><p>Salesforce integrations typically interact with Salesforce via Connected Applications. However, some integrations interact with Salesforce without using a distinct Connected Application, such as some older “legacy” applications, or applications that obtain and utilize access tokens in less-than-ideal ways. Unless the service provider is up-front and identifies that the integration will not work with API Access Control enabled, there is no reliable way to know which integrations or tools may experience problems other than via testing. Even integrations that DO have a Connected Application present may not utilize the Connected App 100% of the time, and the integration may exhibit problems with certain use cases.</p><p>Common integrations that are known to have issues with API Access Control include:</p><ul><li>Salesforce Developer Console</li><li>Salesforce DevOps Center</li><li>Inspector Reloaded</li><li>Others?</li></ul><h3>How to Solve?</h3><p>First, be sure to open support tickets and provide feedback to the service provider regarding the lack of support for Salesforce orgs that utilize API Access Control. The lack of proper support for API Access Control should be viewed as a sign that the solution is either immature or antiquated and should be weighed appropriately when evaluating solutions.</p><p>Second, when API Access Control is enabled Salesforce automatically adds a new system permission called “Use Any API Client”. Users assigned this permission are allowed to use any integration, <em>even Connected Applications that have been deliberately blocked</em>. As Salesforce documentation highlights:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ri_P-kEGuuJ5MuR7Tw-GoQ.png" /></figure><p>Assigning the “Use Any API Client” permission may be a necessary and appropriate solution in some scenarios, especially in sandbox environments, but care must be taken to ensure this permission is appropriately managed in production environments.</p><blockquote>To date, enabling API Access Control has not been known to interfere with integrations commonly used by regular business users, rather impacts and the potential need for the “Use Any API Client” permission have been limited to integration users and users in an engineering role. YMMV.</blockquote><h3>Resource</h3><ul><li><a href="https://help.salesforce.com/s/articleView?id=xcloud.security_api_access_control_about.htm&amp;type=5">Manage API Access</a></li><li><a href="https://help.salesforce.com/s/articleView?id=004637119&amp;type=1">Developer Console known issue</a></li><li><a href="https://help.salesforce.com/s/articleView?id=platform.devops_center_disable_api_access_control.htm&amp;type=5">DevOps Center</a> (<em>don’t</em> follow the advice to disable API Access Control, assign the “Use Any API Client” instead)</li><li><a href="https://ideas.salesforce.com/s/idea/a0B8W00000Gdq50UAB/developer-console-not-fully-consistent-with-salesforce-api-access">Idea: Developer Console not fully consistent with Salesforce API access</a></li><li><a href="https://ideas.salesforce.com/s/idea/a0B8W00000QcGF5UAN/provide-a-permission-to-control-access-to-apis-that-dont-use-a-connected-app">Idea: Provide a permission to control access to APIs that don’t use a connected app</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a45254a42e4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Execute Anonymous Apex Risks and Alternatives]]></title>
            <link>https://medium.com/@feldhacker.chris/execute-anonymous-apex-risks-and-alternatives-9cc1595c78a6?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/9cc1595c78a6</guid>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Mon, 14 Oct 2024 20:57:54 GMT</pubDate>
            <atom:updated>2026-07-24T16:12:07.269Z</atom:updated>
            <content:encoded><![CDATA[<p>Guidance for practical Salesforce customers in the quest for improved security</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kBEQJ4k8w0mwt7Xj" /><figcaption>Photo by <a href="https://unsplash.com/@chrisyangchrisfilm?utm_source=medium&amp;utm_medium=referral">Chris Yang</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Background</h3><p>The Salesforce platform has the inherent capability to execute anonymous blocks of Apex code. Anonymous Apex is a block of code that doesn’t get stored in the metadata or saved in a file, but is ad-hoc code provided by the user that can be compiled and executed on the platform. “Execute Anonymous” is the term commonly used to refer to this capability, which matches the term used in developer tools and the SOAP API.</p><h3>Tools</h3><p>Anonymous Apex code can be executed through several interfaces and tools, including:</p><ul><li>Developer Console</li><li>Salesforce extensions for Visual Studio Code</li><li>Salesforce CLI</li><li>The executeAnonymous() SOAP API call</li></ul><h3>Permissions</h3><p>Executing anonymous Apex requires the user permissions “API Enabled” and “Author Apex”. Additional permissions may be required depending on the tool used and the functionality of the code block being executed. For example:</p><ul><li>The “View All Data” permission is needed just to even access the Developer Console.</li><li>If an anonymous Apex callout references a named credential as the endpoint, then the permission “Customize Application” is also required.</li></ul><p>However, it may be surprising to learn that all users with the “API Enabled” permission have the ability to execute at least <em>some</em> anonymous Apex, even without the “Author Apex” permission. Such users are permitted to execute:</p><ul><li>Code that they write in the anonymous block</li><li>Web service methods (methods declared with the webservice keyword) that are saved in the org</li><li>Any built-in Apex methods that are part of the Apex language</li></ul><p>Running any other Apex code isn’t allowed when the user doesn’t have the “Author Apex” permission. For example, calling methods of custom Apex classes that are saved in the org isn’t allowed nor is using custom classes as arguments to built-in methods. (Source: <a href="https://developer.salesforce.com/docs/atlas.en-us.252.0.apexcode.meta/apexcode/apex_anonymous_block.htm">Anonymous Blocks</a>)</p><h3>Behavior Highlight</h3><p><a href="https://help.salesforce.com/s/articleView?id=sf.code_dev_console_execute_anonymous.htm&amp;type=5">Salesforce documentation</a> on anonymous Apex highlights:</p><blockquote>Important: Every time you run ExecuteAnonymous, the code and its references are compiled. For repetitive calls, we strongly recommend you use compiled classes, such as Apex REST endpoints.</blockquote><p>Similar to Java, Apex must be compiled before it can be executed by the runtime interpreter. While it makes sense that every anonymous block must be compiled, as the excerpt above indicates “the code <em>and its references</em> are compiled”. If the anonymous Apex references other custom Apex classes saved within the org, then those referenced classes are also (re)compiled, and the recompiling continues to cascade down the chain of dependencies. While not counted against transaction runtime limits, compiling does consume CPU and DB resources, which are shared by all users within an org. Apex classes that are recompiled also cause caches to be invalidated, which impacts other users in the org causing delays of indeterminant amounts of time. Once compiling is complete, the anonymous block is executed and then discarded.</p><p>Executing anonymous Apex can vary in duration and resource intensity depending on the exact code being executed, but has roughly the same impact as if an Apex metadata deployment occurred.</p><h3>Key Risks</h3><p>The Execute Anonymous Apex feature presents a number of risks across a variety of aspects.</p><ol><li>Arbitrary Code Execution (ACE) is typically considered a software vulnerability, but on the Salesforce platform executing anonymous blocks of Apex code is a built-in feature. Although users are able to provide arbitrary code to be executed, the Salesforce platform does contain at least some built-in guardrails and constraints intended to reduce the risk compared to other platforms. However, the likelihood of a user being able to leverage anonymous Apex to manipulate production data or to elevate privileges and circumvent security controls is high.</li><li>From another perspective, Execute Anonymous effectively provides a “backdoor” into the Salesforce platform. In a Salesforce org, Apex is intended to be executed through well-defined interfaces, such as a UI controller, an exposed web service, or even behind-the-scenes mechanisms like database triggers, batch classes, or scheduled jobs. Through well-defined interfaces and extension points, code execution pathways are understood and tested to ensure expected behaviors and outcomes. Execute Anonymous allows unknown and potentially untested pathways to be executed and may result in unexpected outcomes. “System code” that was intentionally designed and risk-appropriate when invoked through expected interfaces may present a security risk when invoked through the Execute Anonymous “backdoor”.</li><li>Anonymous Apex blocks of code cannot be logged or audited. Although Salesforce Event Logs are able to identify when Execute Anonymous is used and the user that performed the action, the exact block of code executed is not logged. Whether or not the code being executed is appropriate or outright malicious is entirely dependent on the trustworthiness of the user and the effectiveness of any change processes and controls that have been established. (See: <a href="https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_eventlogfile_apexexecution.htm">Apex Execution Event Type</a>, where Quiddity = ‘X’)</li><li>The risk of human error is high and quality assurance guarantees are low. Even if a block of anonymous Apex is tested and validated in sandbox environments, copy and paste errors can occur. Tools used to Execute Anonymous accept any sequence of text as input, and as long as the text contains syntactically correct Apex, it will be executed with no ability to rollback the transaction. Given a multi-line anonymous block of Apex, inadvertently missing a line when copying from documentation can produce radically different and unexpected outcomes. Last minute tweaks and changes can result in typos that have a meaningful impact.</li><li>Executing anonymous blocks of Apex and the inherent compilation and recompilation that occurs can impact org performance and availability, especially for larger orgs. The exact impact will vary wildly depending on the exact code being executed, the time of day, and other activity stressing the org.</li></ol><h3>Does Execute Anonymous Have Legitimate Uses?</h3><p>It’s important to recognize that Execute Anonymous alters production data or processing, and changes to production systems are typically strictly controlled in many companies, as governed by company security and compliance policies. Allowing or prohibiting Execute Anonymous usage is ultimately a <em>choice</em>, and decisions can be made by appropriate stakeholders after understanding the risks and weighing priorities.</p><p>Operations staff may share feedback suggesting Execute Anonymous does have legitimate uses, namely in “emergency” situations where corrective action is needed to address an adverse event, and executing a block of anonymous Apex code is the most time-efficient remedy available. However, there <strong>are</strong> other solutions to using Execute Anonymous, but they may take more time. In many companies, other stakeholders exist that usually have an opinion this topic, such as security engineers, compliance experts, and senior leadership.</p><p>Execute Anonymous and the “backdoor” abilities it provides can often be a “quick and dirty” solution to a problem, when <em>speed</em> is prioritized above all other concerns.</p><p>Stakeholders and decision makers must make it clear the scenarios in which <em>speed</em> truly is top priority, greater than the all the risks involved and by-passing standard production change pathways is justified. Do any such scenarios exist? Many companies <strong>do</strong> prohibit using Execute Anonymous in production entirely, and Salesforce orgs looking to improve their security posture would be wise to follow suit.</p><p>When it comes to sandbox environments, the confidentiality, integrity, and availability concerns are often reduced, so executing anonymous blocks of Apex can be effective for exploring or experimenting without the rigor typically required in a production org. But if engineers rely on this capability for sandbox environments, what’s the plan for production?</p><h3>Alternative Solutions</h3><p>Execute Anonymous alternatives depend on the use case, but here are some of the most common use cases and suggested alternatives:</p><ol><li>Executing a batch job. Salesforce does not provide a means of executing batch jobs via UI, but it does provide a UI for scheduling Apex jobs (Setup &gt; Custom Code &gt; Apex Classes &gt; Schedule Apex). Therefore, the most feasible alternative is to create a corresponding Schedulable class that launches the batch job, and schedule it to execute immediately. The “Author Apex” permission is required to create or modify Scheduled Apex jobs, but “Modify All Data” is required to delete an existing job.</li><li>Scheduling jobs the UI can’t handle. The Schedule Apex UI <em>used</em> to only support limited scheduling options, but with the Winter 24 release a Cron Expression can now be specified which makes job scheduling much more flexible.</li><li>Bulk update of records. Using tools like Data Loader to update existing records are always worth keeping in mind. For updates requiring more complicated logic, create a schedulable batch Apex job to perform the operations desired, and push the code through the SDLC process like any other change, while reaping the benefits of unit tests, code reviews, and any other change controls to minimize risks and ensure expected outcomes are delivered.</li><li>Business-specific operational tasks. Sometimes processes fail and action is needed to recover the system or deal with anomalies, which are all highly specific to the customizations made within the org. Rather than relying on Execute Anonymous, consider creating and deploying an admin-facing “Ops Toolbox” that supports performing those operational activities. Code can be executed via UI button or action, or perhaps even a screen flow could be created to gather input parameters and perform validation before performing some operation. This solution works best for operational tasks that are known to reoccur, one-off tasks might require a “hotfix” to get them added and deployed.</li></ol><p>Of course, these are just some example alternatives — gather resources and brainstorm away at other options that might be more appropriate for the use cases within your org.</p><h3>Conclusions &amp; Guidance</h3><p>Ideally, organizations that prioritize security, compliance, and change control adherence over mean time to repair (MTTR) metrics should prohibit the use of Execute Anonymous in production orgs.</p><p>For organizations where Execute Anonymous is currently allowed or may have flown under-the-radar until now, consider the following recommendations to begin to <em>change the course of the ship</em>, if you will:</p><ol><li>Recognize that using Execute Anonymous is changing production data or processing, and many companies have production change controls in place that might be relevant. Are relevant stakeholders aware of how and when Execute Anonymous is used and what risks are being accepted? Rising awareness is often the first step to making improvements.</li><li>When Execute Anonymous is used, executing a single line of code typically carries less risk than executing a multi-line block of code. Ops staff may want to consider collaborating with developers to deliver solutions or utilities that make single-line executions possible.</li><li>Execute Anonymous usage should be treated with the same level of caution and diligence as performing a mid-day Apex deployment. Some high-volume orgs may prohibit deployments during core hours to minimize potential user impacts; Execute Anonymous usage should be considered in the same vein.</li><li>Execute Anonymous is an inherent feature of the Salesforce platform that cannot be disabled entirely, but assignment of the “Author Apex” permission can be controlled and audited.</li><li>Execute Anonymous usage can be monitored using the Salesforce Apex Execution Event Logs, and the data used to drive a reduction in use to “exceptional” levels.</li><li>If Execute Anonymous usage is anticipated or used repeatedly, this is an indicator that solutioning is incomplete and alternative solutions should be devised. Any of the “alternative solution” ideas provided above enable Execute Anonymous to shift from being “ordinary” to “extraordinary”, and potentially eliminated entirely.</li></ol><p>Prohibiting, or at least monitoring and reducing, Execute Anonymous usage is a prudent step toward improving the security of a Salesforce org.</p><blockquote>Update: With the Summer 26 release, Salesforce provides a release update to <a href="https://help.salesforce.com/s/articleView?id=release-notes.rn_apex_block_exec_anon_ru.htm&amp;release=262&amp;type=5">Block Apex Anonymous Code Execution from Managed Packages (Release Update)</a> that will be auto-enabled in Summer 27. Enabling this Release Update ASAP is recommended. Hopefully Salesforce will continue to provide additional control over Anonymous Apex in the future!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9cc1595c78a6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Time to Retire Salesforce Network Access]]></title>
            <link>https://medium.com/@feldhacker.chris/time-to-retire-salesforce-network-access-1459860eb46d?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/1459860eb46d</guid>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Mon, 16 Sep 2024 21:28:07 GMT</pubDate>
            <atom:updated>2025-09-30T18:09:19.998Z</atom:updated>
            <content:encoded><![CDATA[<p>Retiring Salesforce Network Access as a Step Toward Zero Trust Security</p><blockquote>Update: Salesforce made improvements related to device activation and network access IP ranges <a href="https://help.salesforce.com/s/articleView?id=release-notes.rn_security_device_activation_changes.htm&amp;release=258&amp;type=5">sometime during the Summer 25 release</a>. Some of the details in this article may no longer be accurate, but the process of reviewing and vetting IPs may still be beneficial to some readers.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5kvZThxwOz6DmDBf" /><figcaption>Photo by <a href="https://unsplash.com/@thatanimeweirdo?utm_source=medium&amp;utm_medium=referral">Laura Heimann</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><blockquote>The main concept behind the zero trust security model is “never trust, always verify”, which means that users and devices should not be trusted by default, even if they are connected to a permissioned network such as a corporate LAN and even if they were previously verified. (<a href="https://en.wikipedia.org/wiki/Zero_trust_security_model">Wikipedia</a>)</blockquote><h3>What is Network Access?</h3><p>Salesforce orgs have a section within Setup called “Network Access”, which allows an admin to specify one or more IP address ranges “that your organization trusts.” When adding an IP address range, the purpose of this feature is explained further: “Users logging in from trusted IP addresses are not asked to activate their computers and may use their user password instead of a security token to log in to the API or a desktop client.”</p><p>To be clear, Network Access is <strong>not</strong> an allow-list. Users accessing Salesforce from an IP address outside the defined range are not prevented from logging in. Rather, users are required to perform an additional step to “activate” their computer (for example, being emailed an access code). Or, in the case of logging in via API, users will be required to provide both their password <em>and</em> security token.</p><p>Essentially, Salesforce offered a rudimentary form of multi-factor authentication years before mobile devices and Authenticator apps where commonplace, and adding IP addresses to the Network Access list offered a means to <em>opt out</em> of the extra authentication.</p><h3>Wait, doesn’t Salesforce now require MFA?</h3><p>Yes…mostly. As of February 1, 2022, there is a contractual requirement for every login through the Salesforce user interface to use MFA (<a href="https://help.salesforce.com/s/articleView?id=000396727&amp;type=1">Salesforce MFA FAQ</a>), and Salesforce has taken gradual steps to enforce this requirement. There are exceptions and ways of flagging certain users as “exempt” from MFA, and customers can choose to enforce MFA requirements through an SSO provider rather than directly within Salesforce. At the end of the day, MFA requirements and enforcement only applies to “user interface” logins (meaning, via web browser) and not API logins.</p><p>For those that are wondering, yes, the MFA requirement <em>does </em>trump the Network Access settings — MFA will be enforced even if the user is accessing Salesforce from one of the IP addresses on the Network Access list.</p><p>It can all get a little bit messy and confusing.</p><h3>So, how is Network Access still relevant today?</h3><p>In short, it’s not — or at least it shouldn’t be. Technically speaking, a Salesforce org may have a sliver of users where Network Access still comes in to play, such as users with the “Waive Multi-Factor Authentication for Exempt Users” permission, or perhaps integration users where API logins might occur.</p><p>Protecting against stolen or phished credentials is a good thing, so continuing to utilize Network Access just lowers a guard.</p><p>It’s time to retire Salesforce Network Access.</p><p>Salesforce has not announced plans to retire the Network Access feature yet, so eliminating the Network Access feature today is a <em>choice</em> that org owners can make to move toward a zero trust security model and make access administration a little bit easier.</p><p>Below is the story of how one large org accomplished this goal.</p><h3>Retiring the Network Access List</h3><p>The goal is to have <strong>no </strong>IP addresses listed in the Network Access section.</p><p>One approach might be to just bravely delete all the IP address entries and be done with it. While most users wouldn’t be impacted since they are using using MFA and/or SSO, the greatest risk for potential impact is to integrations that are using usernames and passwords and <strong>not</strong> also providing a security token. Since org integrations tend to be important, a more deliberate and cautious approach is warranted.</p><p>The Network Access list for the org had about 50 entries that were added over the years, with very few Description fields populated. Seems about right. So how can an admin discover what purpose an IP address might serve?</p><h3>WhoIs Internet Tool</h3><p>WhoIs is a public database that contains information about the various servers and sites on the internet, and a variety of service providers offer tools for querying this database. Examples include <a href="https://who.is/">https://who.is</a> and <a href="https://lookup.icann.org/">https://lookup.icann.org/</a>. Provide an IP address and the tool will return all the information that is known about the address, including the company or person behind it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*_8Gq0HlWdcb5KgnftX7h9g.png" /></figure><p>In the above example, the IP address 13.111.250.0 falls within a range of IP addresses that are registered to Salesforce.com.</p><p>Plugging each IP address into a WhoIs tool can often provide useful insight into how the IP address might be related to the org.</p><p>Using WhoIs on each of the entries in the Network Access list revealed five different categories of IP addresses.</p><ol><li>Private (Invalid) IPs</li><li>Internet Service Providers</li><li>Salesforce and Other “Known” Third-Parties</li><li>Common Cloud Providers (AWS, GCP, Azure)</li><li>The Company’s Own Network</li></ol><h3>1. Private (Invalid) IPs</h3><p>There are certain blocks of IP addresses that are considered “private” and cannot be used on the public internet. IPs such as 10.*.*.* and 192.168.*.*, among others. (See Wikipedia: <a href="https://en.wikipedia.org/wiki/Private_network">Private Network</a>) For unknown reasons, several private IP addresses had been added to the org’s Network Access list over the years. Private IP addresses are completely invalid and have no possibility of actually being used, so these IP addresses could be immediately purged.</p><h3>2. Internet Service Providers</h3><p>WhoIs lookup of several IP addresses revealed company names such as Comcast or Mediacom, which are internet service providers common in the region. The IP addresses that an ISP assigns to subscribers is typically dynamic and may change every few days. More than likely, some admins added their own IP addresses to the Network Access list in the early days of the pandemic when working from home to eliminate an extra login step, and those IP addresses were just never removed or kept up-to-date. Whatever the reason, it is not appropriate to have IP addresses of ISPs included on the Network Access list. These IP addresses could also be aggressively removed.</p><h3>3. Salesforce and Other “Known” Third-Parties</h3><p>Salesforce support and documentation will often instruct “make sure the following IP addresses have been added to your company’s allow-list”, followed by a list of a dozen or more IPs. Multiple admins have acted on instructions like this by adding the IPs to the Network Access list. However, as emphasized in the beginning of this article, the Network Access list is <strong>not</strong> an allow-list, so admins that added to the list under this false belief were acting in error. Vendors of other integrations also provided similar instructions, so IP addresses from these other vendors were found on the Network Access list as well. Some vendors were known to be obsolete and could be easily removed.</p><p>Now, it’s certainly possible that integrations from the remaining vendors might be connecting using username and password and <em>could</em> be impacted if IPs are removed from the Network Access list too aggressively, so a little more diligence might be needed. For now, these IPs were noted and the assessment continued.</p><h3>4. Common Cloud Providers</h3><p>Companies today may utilize one or more cloud providers for a variety of reasons, and several IPs were found on the Network Access list that were associated to well-known cloud providers, such as AWS, GCP, and Azure. Since the company was known to own accounts at each of the big cloud providers, the clients connecting to the Salesforce org might be managed by the company itself, or they might be owned by some other third party. Regardless, the conclusion was the same: maybe integrations hosted by these cloud providers would be impacted by removing their IP address, maybe not. Again, a little more research was needed.</p><h3>5. The Company’s Own Network</h3><p>Finally, the IP address range belonging to the company itself was included on the Network Access list. Because the company controlled the devices that could connect to the network, this is the one entry that could be legitimately deemed “trusted”. If the org was looking to just <em>clean up</em> the Network Access list, removing all entries except for the company’s own network would make sense. But just doing some light clean up wasn’t the goal, achieving Zero Trust was a deliberate choice that was being made, and that meant removing everything.</p><p>The company had a lot of on-premise integrations with various “systems of record” and other platforms, so removing this final IP address block was expected to require more research and caution than all the others.</p><h3>IP Address Usage — Login History</h3><p>By leveraging the WhoIs tool and performing a quick pass through the list of IPs, it was possible to eliminate a <em>majority</em> of the entries on the Network Access list. About 15–20 entries remained that deserved some deeper impact analysis and more certainty before purging. If logins were occurring for a given IP address using username and password (and no security token), then integrations could break. How do you know if an IP address is being used?</p><p>Every Salesforce org maintains at least 6 months of login history data, which admins can download and analyze (Setup &gt; Identity &gt; Login History). For orgs with Shield or the Event Monitoring add-on, the Event Monitoring application in CRM Analytics is also available to help analyze about 30 days of login data.</p><p>The Login History data was first filtered where the field LoginSubType = “OAuth Username-Password”. While other authentication types may be in use, this is the OAuth flow that requires a user to provide a security token in addition to the password.</p><p>The filtered Login History was then searched for each of the IP addresses remaining on the Network Access list. Note that some entries included an IP <em>range</em>, not just a single IP. If a given IP address or range was not found in the Login History, the IP was not being actively used and could be removed.</p><h3>Login History Results</h3><p>When all analysis was complete, the only IP addresses actively being used with “OAuth Username-Password” authentication were the IP ranges belonging to the company itself, all other IP addresses could be removed.</p><p>However, over 50 distinct integration users were found to be connected from the IP range! Achieving zero trust was going to take some more work!</p><h3>Preparing Integrations</h3><p>Collaborating and communicating with integration owners was required to prepare them for the upcoming removal of the company’s IP address range.</p><p>Some integration owners knew a security token was being used and would experience no impact. Some integration owners were unsure, or knew a security token was not being used, so the security token needed to be retrieved and added to the client application.</p><blockquote>A Salesforce gotcha: When logging in from an IP address that is on the Network Access list, it is not possible for the user to request their Security Access Token. Because it’s not needed. Because the user is logging in from a trusted IP. Argh! This catch-22 can present quite a conundrum, and the only solution is for the user to login from an IP address not currently on the Network Access list. Good luck!</blockquote><p>Also note: the OAuth Username-Password flow is considered one of the least secure, and alternative flows should be favored instead, flows that don’t require a security token. While some integrations where updated to use the OAuth Client Credential Flow, others still required the use of Username-Password Flow because reasons.</p><h3>Gradual Rollout and Monitoring</h3><p>Most of the integrations run continuously in the production org as well as the UAT sandbox. Once integration owners <em>thought</em> they were prepared, the final IP address block was removed from the Network Access list in the UAT environment.</p><p>The Login History event logs were then monitored looking for records with the Status of “Failed: API security token required”, indicating that an integration user had been missed or the security token not properly added as required. Integration owners had a second opportunity to make sure production applications were properly updated.</p><p>Once sufficient time had passed with sandbox environments running “clean” and no additional login failures, the Network Access list was finally purged in the production org. Login event monitoring continued in production, which identified only one integration user experiencing login failures and was quickly remedied.</p><p>Success!</p><h3>Benefits</h3><p>Because no network is considered “trusted”, phished or stolen credentials alone are not sufficient to access a Salesforce org as extra verification will always be required.</p><p>Maintainability of the Salesforce org also improved as the Network Access section was often poorly understood and a source of confusion. Now, the Network Access list is completely empty, and policies established to make it clear nothing should be added to the list ever again.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1459860eb46d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Overuse of Salesforce User Context Increases Security Risk (Part 2)]]></title>
            <link>https://medium.com/@feldhacker.chris/how-overuse-of-salesforce-user-context-increases-security-risk-part-2-2a9d69cc3a32?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a9d69cc3a32</guid>
            <category><![CDATA[salesforce-development]]></category>
            <category><![CDATA[salesforce-security-model]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 18 Jul 2024 22:34:20 GMT</pubDate>
            <atom:updated>2024-07-18T22:34:20.328Z</atom:updated>
            <content:encoded><![CDATA[<p>Part 2 — Cascading Impacts</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qFEompJt51GQtd_0" /><figcaption>Photo by <a href="https://unsplash.com/@bradyn?utm_source=medium&amp;utm_medium=referral">Bradyn Trollip</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>(Continued from <a href="https://medium.com/@feldhacker.chris/how-overuse-of-salesforce-user-context-increases-security-risk-part-1-1de2e91ac953">Part 1 — Direct Impact</a>)</p><p>Suppose the hypothetical business requirements and systems automations were implemented as described in Part 1, and there was a desire to accept the additional permissions that needed to be assigned to users. Several additional problems surface when deploying this new solution.</p><h3>Deployment Impact — Impacted Personas</h3><p>It is necessary to identify all of the users (personas) that can perform Account address changes, as all of these personas will need to be assigned additional permissions for the solution to work properly. If a persona was missed, users would either receive an error when performing an address change, or the expected behind-the-scenes functionality might just fail silently. (The exact behavior would depend on exactly how the solution was coded, but errors are typically the most common result.) In a large org with many personas, this could mean dozens of personas are impacted. Presumably, some querying would be needed to identify all the users that currently have access to edit Account address fields, as those users would all require the additional permissions required by the new behind-the-scenes automation the business needs. It would then be necessary to determine which personas these users fall into.</p><h3>Impacted Personas — Personas Stewards</h3><p>In a large org, different personas may be administered by different “stewards”, and it may be necessary to communicate and coordinate permission changes through multiple steward groups. When the steward groups are presented with the list of permissions that need to be added, if just one steward group raises an objection, then there’s a problem. Perhaps some personas are less trustworthy than others, or some personas may have access to additional APIs and/or tools that make granting the additional permissions even more risky. As good practitioners of “minimum access” security, stewards <em>should</em> raise objections if they believe the personas they are responsible for are being over-provisioned with permissions. If a single steward group <em>does </em>object, then either the feature cannot be deployed as-is and must be redesigned (if possible), or appropriate escalations need to occur that <em>forces </em>the persona stewards to accept the increased risk from the additional permissions needed. (The business wants this feature out the door yesterday!)</p><h3>Impacted Personas — Permission Assignments</h3><p>Even if all steward groups accept the additional permissions needed, if those steward groups are also responsible for the deployment/assignment of the needed permissions to the personas they are responsible for, each steward group may prioritize the deploy of those permissions differently, resulting in delays for the feature. Alternatively, the steward groups could also choose to trust the feature developers to make the necessary changes to the profiles / permission sets / permissions set groups for which the steward group is responsible. (Some steward groups may be leery having been burned by unexpected changes and human errors in the past.)</p><h3>Deployment Impact — Sequence of Changes</h3><p>Assuming approvals, risk acceptance, and timelines among all the steward groups have all been figured out, there are still some technical deployment hurdles to work through, which can often times present a chicken-and-egg problem. Keep in mind that the moment the new system automation is deployed, users will begin encountering errors when changing addresses unless everything is in place and all the needed permissions have been assigned. If all metadata changes and permission assignments can be achieved within a single deployment, great! A zero-downtime feature deployment might be possible. However, there are also situations that can cause complications, such as:</p><p><strong>1. Change Ownership</strong></p><p>If even one steward group is protective of the identity elements they are responsible for and choose not to allow modifications by admins outside the group, this might be a driver for multiple, separate deployments.</p><p><strong>2. Different Permission Management Strategies</strong></p><p>Different steward groups may be at different levels of maturity in how permissions are managed, or different steward groups may have deliberately made different choices. For example, Salesforce is soon moving away from supporting permissions within profiles and will be supporting permissions within permission sets only. Some steward groups may have already embraced the new model with the the personas they manage, while other steward groups might still be managing profiles. Even among the steward groups that might be considered “mature” and are trying to stay ahead of Salesforce permission changes, there are different philosophies on how to structure and manage permission sets, such as object-based, application-based, persona-based, etc.</p><p>In a large org, <em>multiple</em> approaches may even be utilized, for good reasons. Even if the team that delivered the new system automation also provided a “Account Address Change Automation Feature” permission set containing all the necessary permission for the new feature to properly function, some steward groups might be able to utilize the provided permission set as-is, some might not. Some steward groups might have an easy time assigning needed permissions to the users in their persona(s), while for other steward groups unexpected assignments as required by a feature like this might be more difficult. Assuming that all metadata changes <em>and </em>permission assignments can be accomplished in a single deployment might be unrealistic depending on the org.</p><p><strong>3. Required Dependencies</strong></p><p>Regardless of the reason, if a single deployment cannot be achieved, then two or three separate deployments may be required and need to be carefully sequenced in order to ensure users do not experience errors mid-change. Consider:</p><ul><li>First, all new objects and fields need to exist. If the new feature involved the creation of a new object or field (such as the hypothetical LicenseReview object), it’s not possible to deploy a permission set that references objects/fields that do not yet exist. Likewise, it is not possible to deploy Apex code that references objects/fields that do not exist. New objects and fields must be deployed first.</li><li>Second, permissions need to be assigned to all impacted users, however the personas stewards each decided is most appropriate. There may be one or multiple approaches to ensure needed permissions are assigned, which might be as easy as adding to an existing permission set group, modifying an existing profile or permission set, or (not ideal) bulk creating PermissionSetAssignment records, perhaps using Data Loader. Or, perhaps the new User Access Profile feature from Salesforce may be useful to selectively apply a permission set to users based on some criteria. In any event, users must have the needed permissions assigned first before any system logic can be executed that expects the permissions to be there.</li><li>Finally, the Apex code containing the needed business logic can be deployed, as all needed dependencies (objects, fields, permissions, and assignments) have been put into place.</li></ul><p>But the implications of the User Context approach do not end there.</p><h3>Deployment Impact — Time</h3><p>In a large org, the deployment of a single non-Apex configuration change can still take 15–20 minutes. So the deployment of the feature in the hypothetical example may take an hour or more before it is complete across multiple transactions. But, by carefully orchestrating the deployment in phases, users did not experience any errors during the interim system states.</p><h3>Permission Set Limits — Permission Merging</h3><p>It was suggested above that perhaps the developers of the new behind-the-scenes system automation that required new permissions be assigned for proper functionality might also provide a permission set, maybe named “Account Address Change Automation Feature“, that contains the exact permissions needed. This is very considerate and thoughtful of the developers to provide!</p><p>However, how many “features” make up a large org? How about after 5+ years of enhancement requests across multiple lines of businesses, product domains, and business processes being worked on in an org with a couple hundred Salesforce administrators? 1000 features? 10,000 features?</p><p>The idea of a Permission Set per feature might seem like a good approach at first, but it’s not sustainable or scalable. It’s also worth noting that Salesforce has a limit of 1000 custom permission sets usable to customers orgs (effectively), with a reported hard limit of 2000. If even half the limit is consumed by persona stewards for “normal” usage, that really doesn’t leave very many permission sets left to support a feature-based permission set strategy.</p><p>Soon, features get combined and merged together in attempt to keep the number of permission sets manageable and under Salesforce org limits. Conway’s Law tells us that features will be combined in ways that reflect the company’s org structure or team structure, not necessarily in ways that group related functionality together. (It’s not about what the feature does, it’s about which team of developers wrote the code, right? /s) The permissions needed for behind-the-scenes automations to function correctly grows more numerous. If persona stewards were concerned about the risks of over-provisioning users before, users will be granted even <em>more</em> permissions now. Keep in mind these are permissions that are <em>required</em> by the system; saying “no” causes the system to break.</p><h3>User Context Impact — Testing</h3><p>The testing impact was alluded to briefly in the previous section, but it’s an important enough topic to callout explicitly. As stated above: “It is necessary to identify all of the users (personas) that can perform Account address changes, as all of these personas will need to be assigned additional permissions for the solution to work properly.” Also, “different steward groups may be at different levels of maturity in how permissions are managed, or different steward groups may have deliberately made different choices. “</p><p>As a result, assuming all impacted personas have been identified, making the necessary permission changes may be easier said than done. Of course the core system behavior requires functional testing, but testing the code developers created is only half the change. The other half of the change involves new permission assignments to potentially dozens of personas which may have been made in a variety of ways. Testing of the new functionality across each of the impacted personas to validate the <em>permission assignment </em>changes will be performed, too, right? (Yes, the answer is yes.) Functional testing is not persona-agnostic, rather functional testing is persona-<em>dependent </em>and must be accounted for to adequately test <em>all</em> the changes being made. The amount of effort required for testing is multiplied by the number of personas impacted. In a large org, this is not a trivial amount of effort.</p><p>But the implications of the User Context approach do not end there.</p><h3>User Context Impact — New Personas</h3><p>Suppose the hypothetical business requirements and systems automations were implemented as described above, persona stewards all accepted the risk (one way or another) of the additional permissions that had to be assigned, priorities and timelines where coordinated, dependencies were figured out, and the new system automation behind Account address changes was successfully deployed. Time passes, business evolves.</p><p>Suppose a new group of end users needs to be onboarded into the Salesforce org, a new persona created, and the users need to be able to modify Account addresses. As the steward(s) responsible for setting up this new persona, granting edit access to Account address fields is obvious. But wasn’t there some behind-the-scenes automation put in place last year that required the user to have additional permissions to function properly, what was that? Which team worked on that? What additional permissions were needed? Was that documented? And kept up-to-date? And didn’t that other team have to make a change that one time because the primary team was too busy — what did they do again, and did they remember to update the documentation? Wait a minute — did that other team even update the feature permission set, or did they just add another field to the automation and deploy it and the new code <em>just happened</em> to work for most users because most users <em>just happened</em> to have already been granted access to the additional field for other reasons, not because developers were carefully maintaining the permissions needed to support each feature? (Could this be why the org is seeing several hundred unhandled exceptions every week, many of them pointing to permission issues, and pockets of users are reporting sporadic errors but the users can’t identify what exactly they are doing differently so it’s a challenge to even reproduce the errors?)</p><blockquote>The above example highlights another aspect where distinct impacts are felt: “future enhancements”. Future enhancements to the system require careful attention and diligence regarding any new permission needs that may be introduced, and developers must communicate new permission requirements to be incorporated by persona stewards appropriately. If an enhancement is later requested for automation to be added when LicenseReview records are created, developers may not even be aware of the need to consider the implications to the Account address change feature and all of those personas.</blockquote><blockquote>Another related impact involves “code reuse”. Suppose there exists a “service” class in Apex that performs some useful piece of functionality, but that functionality also involves generating a record in an AuditLog object, for example, or other behind-the-scenes behaviors. Code reuse is good thing, but now code reuse comes with the added requirement of needing to keep track of all the behind-the-scenes objects and fields that might be needed so additional permissions can be communicated and added to all the personas that may end up executing the reused code. Developers could try creating a Permission Set per service, but the discussion now circles back to talking about limits on the number of Permission Sets and the consequences of Permission Set merging…</blockquote><p>Back to the new persona.</p><p>The new persona being created involves not just one object and field, but maybe a couple dozen objects and hundreds of fields. What should the persona stewards do? Reverse-engineer the automations behind the objects to deduce the permissions needed? Testing trial and error of the new persona in hopes of discovering the additional permissions needed behind-the-scenes? What if a permission is missed? (Could the business ultimately face legal issues if License Review records don’t get created? Could agents waste money traveling to incorrect and outdated meeting locations with clients?) What if the persona stewards discover the system requires a permission to be granted to users that the stewards, still strong advocates for “minimum access”, are certain is completely inappropriate to grant to the users in this new persona?</p><p>Creating a new persona within a Salesforce org where system automations have chosen to enforce User Context can be extremely challenging. While persona stewards would normally only need to focus on what objects and fields are appropriate to grant the new persona to perform the new job function while being focused on the idea of “minimum access”, now stewards must also somehow determine <em>all</em> the permissions a user might require, both direct and <em>indirect</em> permissions.</p><p>⚠️What is a persona steward going to do in practice when a new persona needs to be created? How will the permissions needed be discovered? Documentation will be nonexistent, poor, and/or out-of-date. A large org is comprised of 1000s of “features”.</p><p>Two approaches commonly surface:</p><ol><li>Persona stewards may pull up a list of permission sets, and based solely on the permission set names and description (if there is even is one!), stewards will simply <em>guess </em>at the permission sets that are needed, select a bunch, do some functional testing, and keep adding additional permission sets in attempt to resolve any permissions errors that were encountered. Persona stewards will end up selecting, say, 50 permission sets that allowed permission errors to finally go away, when only maybe 12 permission sets were actually needed had the steward known which permission sets were actually “correct”. The result: the new persona is overprovisioned.</li><li>More likely, persona stewards will attempt to identify an existing persona that is “close enough” to the new persona being created and try to clone it. As security-minded individuals know, “cloning” is the antithesis and arch nemesis of “minimum access”. What if the persona selected to be cloned had access to additional features that required some “elevated” permissions to be assigned which were determined to be risk-appropriate for the group of more senior, tenured employees placed into the persona and not risk-appropriate for the team of employees with a high-churn rate that will be assigned to the <em>new</em> persona? What if the selected persona just happened to have been granted temporary, elevated permissions as a short-term fix in order to resolve a critical system issue that popped up last week, but those permissions are scheduled to be removed next week? Cloning is an anti-pattern to be avoided as it starts with a source of questionable quality and stewardship, and typically <em>adds </em>more permissions and privileges to it. Rarely are existing permissions questioned and removed. The result: the new persona is overprovisioned.</li></ol><p>In either approach, the new persona contains permissions far beyond what is actually required, often times drastically so.</p><h3>User Context Impact — Conclusion</h3><p>The journey down the system-automation-that-chooses-to-enforce-user-context rabbit hole has been long and winding. Not only is risk increased when users must be granted many additional permissions far beyond what is actually appropriate and required by the job function, but the impacts cascade even further to include deployment complications, diligence required when making future enhancements, unexpected implications when it comes to code reuse, challenges and realities involved when spinning-up new personas, and just an overall inability for security-minded persona stewards to achieve “minimum access” goals. Permissions that “the system” forces upon users cannot be refused.</p><h3>Let’s Reconsider — User Context or System Context?</h3><p>As a reminder, this exploratory journey started by focusing on a trigger that needed to execute a few SOQL and DML statements to deliver the desired business outcomes, and a decision was made that these SOQL and DML statements should enforce user permissions. Life became very difficult for…well, for everyone.</p><p>What if a different choice was made?</p><h3>Scenario 2: System Context</h3><p>As a refresher, there’s not exactly a “front door” to a trigger, rather the database is accessed via other interfaces that Salesforce provides, whether the Web UI or an API. Triggers are fired <em>after</em> the request has already reached the database. When thinking about the trigger’s place in the execution pathway, the “front door” has already verified the user permissions to the object/field/record, and is responsible for input validation as well as any output encoding. This is true whether the user supplied data using an API or Web UI, both standard and custom (again, custom “front doors” is a completely separate topic).</p><p>Triggers contain business logic that was written by developers in order to deliver a variety of behaviors and outcomes that the business wants the system to perform. Whatever additional objects/fields/records are being accessed is not driven because the user is attempting to directly access this data, rather because the system <em>requires</em> it. Triggers are designed and created to function they way they do because the business requested it.</p><blockquote>To ensure custom code properly performs the expected actions and nothing extraneous or nefarious, a variety of processes and procedures are often employed, such as code scanning tools, code reviews, and other change control requirements and checkpoints that must be fulfilled (such as a variety of testing) before custom code is allowed to be deployed into the production system. Changes to the production environment are typically made using a “deployment pipeline”, which often leverages one or more tools to aid in the bundling and delivery of a collection of changes through a sequence of one or more sandbox orgs before finally landing in the production org. Controls are in place to ensure developers cannot bypass the pipeline.</blockquote><p>To deliver the hypothetical business requirements, the behind-the-scenes automation created by developers could alternatively choose to utilize System Context for the SOQL and DML statements. If this choice is made, then users are <em>not </em>required to be given the “Access Activities” system permissions, and broader access is not granted to Events, Tasks, Calendar, and Email Message records. The “Edit Events” permission does <em>not</em> need to be granted to users, so users will not have additional abilities to create and delete Events. Granting access to the specific Event fields the system automation needs to update is <em>not </em>required. The OWD for the Activities object is irrelevant, and there does not exist a worse case scenario of needing to grant users “Modify All Data”. Users also do <em>not</em> need to be granted permissions to the License Review object and fields.</p><p>🙋 Back to “Addie Fixer”. Before the system automation was implemented, Addie’s persona was granted the following permissions:</p><ul><li>Object: Account — Modify All object permission</li><li>FLS: Account.Name, Account.RecordType, Account.BillingAddress, Account.ShippingAddress</li><li>Assigned Application: “Data Steward Console” (for example, a custom application designed to support the data steward job function)</li><li>Connected App: Data Loader</li><li>System Permission: Lightning Experience User</li></ul><p>After the system automation was implemented using System Context, the following additional permissions had to be assigned to Addie:</p><ul><li>(None!)</li></ul><p>The permissions assigned to Addie are still appropriate and support the Principle of Least Privilege.</p><h3>System Context Impact</h3><p>In short, there is no need to grant users any additional permissions at all. The implications of this are profound:</p><ol><li>Users can continue to be provisioned with the exact permissions needed to perform the job function, using whatever interfaces (UI) and tools (e.g., Data Loader) deemed appropriate. “Minimum access” permission model can be maintained, the Principle of Least Privilege is being followed. No consideration is needed for the behind-the-scenes automation that has been created within the system.</li><li>There is no need to communicate and coordinate permission changes with persona stewards, and no permission changes means there are no potential security or over-provisioning concerns for stewards to object to. The particular Profile/Permission Set strategies that persona stewards may be using, or how mature those stewards might be in their permission management journey does not matter. No need to identify impacted personas, nor perform redundant functional testing across multiple personas. The system automation either works or it doesn’t consistently across everybody.</li><li>There is no complicated deployment dependencies to figure out due to permissions and assignments, nor multiple phases to orchestrate. The only deployment consideration needed is for the delivery of the automation feature itself.</li><li>Automation developers do not need to diligently keep track of every object and field accessed, nor potentially provide a corresponding “feature permission set”. Permission sets will not grow to unwieldly numbers, and there are no concerns about org permission set limits being hit (at least not due to behind-the-scenes automation reasons). Features and permissions won’t eventually be merged resulting in even more over-provisioning. Conway’s Law could surface in other places, but it’s certainly not going to be allowed to leak through and impact the security model and increase risk due to some behind-the-scenes automation. Code can be freely reused where appropriate without the potential for unexpected permission issues to result in unexpected user errors or unhandled exceptions within the org. Future enhancements can be made without dread.</li><li>When a new group of end users needs to be onboarded into the Salesforce org, a new persona can be created easily. The persona stewards only need to be concerned with the applications, tabs, defaults, objects, and fields the persona directly needs to perform the job function (i.e., “the usual suspects”). There is no need to chase down documentation behind every field hoping it’s up-to-date, or potentially reverse engineer automations to deduce the permissions needed. There is no need to guess and select permission sets from a long list, with even more permission sets being added in attempt to resolve issues found during extensive trial-and-error testing, undoubtedly resulting in an over-provisioning of the new persona. Stewards are less like to clone an existing persona when creating a new persona. Even if cloning <em>does </em>occur, stewards can review the cloned persona and aggressively remove permissions that are inappropriate for the new job function because the stewards know permissions are not needed due to behind-the-scenes reasons. If the user does not <em>directly</em> need a permission, remove it! “Minimum access” can be achieved not only when a persona is initially created, but permissions can be continually challenged and pruned during future permission reviews without fear of system malfunction.</li></ol><p>Whoa.</p><h3>Trigger Conclusion</h3><p>In the context of a trigger performing system automation, choosing to implement System Context is the better choice — not only because it reduces risk and increases security, but because there is a litany of impacts and complex, unintended consequences that result from choosing to enforce user permissions that leads a customer org into a very bad state that is difficult to articulate, difficult to undo, and for which not a lot has been written about.</p><p>Are there exceptions to the rule?<em> Could</em> triggers still use User Context, in some cases? Sure, it’s possible, but rare. Business requirements must never dictate which context to use, but an interpretation of requirements <em>could</em> lead a solution engineer to conclude that User Context (or at least <em>partial</em> User Context) might be appropriate in certain situations. If such an exceptional situation is suspected, be sure to bring in more experienced Salesforce architects to review. All of the User Context implications highlighted previously still apply and cannot be overlooked, and an evaluation of available SOQL/Apex features will likely be necessary to make certain decisions. (For example, in which code pathways should the solution be allowed to generate an error to the user, fail silently, or gracefully remove/avoid inaccessible data instead? Or, maybe a particular solution needs to only impact <em>records</em> accessible to the user, but “the system” still needs to modify required <em>fields </em>irrespective of the user’s permission. What combination of SOQL/Apex security features and keywords should be used to accomplish this?)</p><p>Overuse of User Context increases security risk and can have significant impacts within large customer orgs.</p><h3>Related</h3><p><a href="https://medium.com/@feldhacker.chris/using-salesforce-system-context-in-itself-is-not-a-privilege-escalation-vulnerability-63abf20c5f74">Using Salesforce System Context In Itself Is Not a Privilege Escalation Vulnerability</a></p><h3>Salesforce References</h3><p><a href="https://medium.com/salesforce-architects/how-to-implement-the-principle-of-least-privilege-in-salesforce-59d3dbab9908">How to Implement the Principle of Least Privilege in Salesforce</a></p><p>“How to Implement the Principle of Least Privilege in Salesforce” Highlight:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1014/1*us3job8rscILdisPXDyLdQ.png" /></figure><p><a href="https://developer.salesforce.com/docs/atlas.en-us.secure_coding_guide.meta/secure_coding_guide/secure_coding_authorization_access_control.htm">Authorization and Access Control</a></p><p>“Authorization and Access Control” Highlight:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YVSzDWxhNzfg0fgtuWcIZg.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a9d69cc3a32" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Overuse of Salesforce User Context Increases Security Risk (Part 1)]]></title>
            <link>https://medium.com/@feldhacker.chris/how-overuse-of-salesforce-user-context-increases-security-risk-part-1-1de2e91ac953?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/1de2e91ac953</guid>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-security-model]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 18 Jul 2024 22:31:41 GMT</pubDate>
            <atom:updated>2024-07-19T21:02:44.326Z</atom:updated>
            <content:encoded><![CDATA[<p>Part 1 — Direct Impact</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ufUIJpbGpceli2Hh" /><figcaption>Photo by <a href="https://unsplash.com/@enphotos?utm_source=medium&amp;utm_medium=referral">Erica Nilsson</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Standard Behavior</h3><p>Salesforce stores data, lots of data. Before displaying data to the user, it is necessary to make sure the user has been actually granted permission to view the data. This includes making sure the user:</p><ol><li>Is allowed to access the SObject type (object access)</li><li>Is allowed to access the individual field(s) (field-level security, or FLS)</li><li>Is allowed to access the specific record(s) (sharing access)</li></ol><p>When using standard, out-of-the-box Salesforce features, Salesforce enforces all three of the above. This includes when using standard web interface components, like Lightning record pages, page layouts, and dynamic forms.</p><p>To say that user permissions must be enforced before “displaying” data isn’t quite accurate. Rather, it would be more accurate to say user permissions must be enforced before “returning” data to the end user. A web interface is one way that a user is able to access data, but data can also be accessed using APIs, such as SOAP, REST, Graph, Streaming, and UI. Salesforce automatically ensures user permissions are enforced when data is read and returned through all standard APIs.</p><p>Allowing a user to edit data in Salesforce must also be given the same consideration as returning data. Standard interfaces allow a user to edit a record of a specific type that the user has been given permission to update, and the user is allowed to modify and specify new field values, but only for the individual fields that the user has also been granted explicit access to edit. Again, users might supply new data values using a web interface or APIs, and Salesforce automatically enforces object/field/record security through all standard interfaces.</p><h3>Security Configuration Decisions Needed</h3><p>So far the Salesforce platform is secure and Salesforce is fully responsible for permitting and preventing user access to data, based on configurations set by org admins. Relevant security configurations fall into two main categories:</p><ol><li>Org Configuration (Record / Sharing access): This is where several org-wide configurations come in to play, including sharing org wide defaults (OWD), role hierarchy, sharing rules, account/opportunity teams, manual sharing, etc. These settings are foundational to determining which set of records a user is permitted to access.</li><li>User Assigned Permissions — These are permissions that are directly assigned to each user based on what is appropriate for each user’s job function. Two common categories of assigned permissions include:</li></ol><ul><li>Object and FLS — These define the exact objects and fields that the user is permitted to view and/or modify.</li><li>System Permissions — These allow access to specific Salesforce features or “chunks” of related functionality, which may include Objects and FLS, as well as other capabilities or actions.</li></ul><p>All of the above configurations and assignments are applicable to all the interfaces through which the user may access data, such as the web interface, APIs, integrations, and other tools.</p><p>After making intentional decisions about what is risk-appropriate for record / sharing access and configuring the org settings accordingly, then end users can be partitioned into distinct audiences and appropriate user permissions assigned to each. These distinct audiences are typically thought of as “personas”.</p><h3>Permissions Not Always Clear-Cut</h3><p>It is worth highlighting that user assigned permissions can be sometimes challenging to figure out as not all Salesforce data can be precisely controlled. For example, object-level access to Events, Tasks, Calendar, and Emails is controlled through a single system permission called “Access Activities”, while setting FLS on each object is still possible. The system permission “Update Email Messages“ is needed to allow modifying certain email related records.</p><p>Other Salesforce objects are considered “setup objects”, which also require special system permissions and a limited ability to configure. Permissions like “View Roles and Role Hierarchy” might be intuitive, but being able to work with Public Groups requires the “Manage Users” permission, which grants permission to do a lot more than just manage Public Groups.</p><p>The point: Determining the permissions that need to be assigned to a user often requires thoughtful analysis. Some permissions may permit a user to access more data or perform actions that are not risk-appropriate for the user’s job function, so alternative solutions and other considerations may be required.</p><p>🙋 Meet “Addie Fixer”, Account Locale Data Steward, whose sole job is to maintain address information on Accounts, nothing else. The business decided this was an important function to perform and created a specialized team of contractors staffed with Addie and a few others. While Addie typically works in the web UI, she has also been granted access to Data Loader because she often needs to update several records at a time. The permissions assigned to Addie may look like:</p><ul><li>Object: Account — Modify All object permission</li><li>FLS: Account.Name, Account.RecordType, Account.BillingAddress, Account.ShippingAddress</li><li>Assigned Application: “Data Steward Console” (a custom application designed to support the data steward job function, just for example)</li><li>Connected App: Data Loader</li><li>System Permission: Lightning Experience User</li></ul><p>The permissions assigned to Addie are appropriate and support the “least privileged” security principle. We will return to Addie…</p><h3>Platform Customizations</h3><p>When customizations are made to the Salesforce platform, not only do solutions need to be designed to account for platform and transaction limits, but developers must also make a number of decisions to write code that is secure. Several categories of common security vulnerabilities are applicable to every web application, regardless of the application platform. Developers must continuously educate themselves on secure coding practices to build the skills needed for creating applications that defend against common security vulnerabilities. Some example application weaknesses include:</p><ul><li>Improper Access Control</li><li>Improper Neutralization, including Input Validation and Output Encoding <br>(Which can lead to specific vulnerabilities like cross-site scripting, SQL/SOQL injection, command injection, Cross-Site Request Forgery (CSRF), among others that should be familiar to web developers.)</li></ul><p>Full coverage of these topics is well beyond this scope of this discussion, but these common categories are mentioned here because they will be used as a reference point in some considerations that follow.</p><p>Although the Salesforce platform can be customized in many ways, this discussion will focus on an example of some behind-the-scenes automation, while assuming only standard web interfaces and components are used.</p><h3>Apex Triggers</h3><p>Triggers are an extension point that Salesforce provides at the database layer. Meaning, there isn’t exactly a “front door” to a trigger, rather the database is accessed via other interfaces that Salesforce provides, whether the Web UI or an API. Triggers are fired <em>after</em> the request has already reached the database.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lTkYRDS9yVtceSVSqfiaVQ.png" /><figcaption>Simplified trigger view from a Salesforce customer perspective</figcaption></figure><blockquote>Note: Apex best practice is to minimize the amount of code located within the trigger itself, so triggers typically call one or more Apex classes to execute all the desired logic. For this discussion, “triggers” is meant to include the trigger file itself, as well as any trigger frameworks and other Apex classes that may have been created to better organize Apex code. Thus, in a large org, “triggers” could include 100s of Apex class files or more.</blockquote><p>Focusing on the security category of “input validation”, the core Salesforce platform provides some common capabilities regardless of how the database is accessed — Salesforce automatically enforces concerns like type correctness, picklist restrictions, and any custom validation rules that may have been defined. The Web UI provides additional conveniences, such as formatting numbers and offering certain default field values.</p><p>Focusing on the security category of “output encoding”, record values have already been properly encoded before the database transaction was even started, so no addition encoding is required (and <em>double</em>-encoding produces bad data). A trigger cannot really display or return a value to the user, rather a trigger can either succeed or use addError() to report an error condition — throwing an exception is also possible, but “unhandled exceptions” are a bad practice. In any event, it is up to the “front door” (something else upstream) to handle any error that might occur within a trigger, which includes any “output encoding” of the error message.</p><p>Focusing on “access control”, the “front door” has already verified the user permissions to the object/field/record. This is true whether the user supplied data using an API or Web UI, both standard and custom (custom “front doors” are a completely separate topic).</p><p>For a trigger, life is pretty good as many common security concerns are already being handled by the core platform, or at least early in the execution path.</p><h3>What else might a trigger do?</h3><p>Triggers often invoke other Apex classes, which can do just about anything that is supported by the Salesforce platform. Triggers are often created to cause the system to behave or respond in specific ways, as the business has deemed appropriate.</p><p>To aid the discussion and analysis, a contrived example will be introduced that is intended to be simple yet real enough to demonstrate some key topics.</p><p>Hypothetically, suppose there exists business requirements surrounding Account address changes, such that:</p><ol><li>If the street address changes, then the location field of any future Events tied to the Account that contained the old street address must be updated to use the new street address.</li><li>If the state of an Account changes, then a new “License Review” record needs to be created so that the compliance department can perform a review of all of the agents assigned to the Account team to make sure the agents are properly licensed in the designated state.</li></ol><p>A trigger on the Account object is created to deliver on these requirements. At a high level, for proper functionality, when an address field is updated and meets the criteria, the trigger needs to:</p><ul><li>Query existing Event records tied to the Account for all users</li><li>Update existing Event records tied to the Account for all users</li><li>Create new License Review records</li></ul><p>Thus, a number of SOQL and DML statements will be required.</p><h3>User or System Context?</h3><p>A developer focused on secure coding and thinking about access controls has a decision to make: should the trigger execute each SOQL and DML statement using User Context or System Context?</p><blockquote><strong>Terminology Note:</strong> Over the years Salesforce has introduced a number of security-related features in both Apex and SOQL that impacts a user’s ability to access data. Some solutions take into consideration record sharing, some don’t. Some respect FLS, some don’t. Some respect restriction rules, some don’t. Some solutions cause a transaction to fail with an error, while some cause data inaccessible to the user to be removed from results quietly.</blockquote><blockquote>For the purpose of this discussion, the term “User Context” is used to mean the permissions assigned to the user and what the user has explicit access to are being enforced, while the term “System Context” is used to mean the user’s explicitly assigned permissions are not enforced. User and System Context might be achieved using SOQL/DML access keywords, but it could also include other Apex security features or utilities (e.g., “stripInaccessible”) that are used or combined in ways that achieve a similar result.</blockquote><h3>Scenario 1: User Context</h3><p>If the decision is made to use User Context, then this means users will need to be explicitly assigned the permissions needed for the trigger to deliver the behavior required by the business.</p><p>Querying Event records requires the “Access Activities” system permission, which grants access to Event, Task, Calendar, and Email Message records. Although setting FLS for each object is possible, Salesforce forcibly provides read and even edit access to a number of fields: Events (14 read/edit fields plus 4 read only fields), Tasks (12 read/edit fields plus 7 read only fields), and Email Message (10 read/edit fields plus 16 read only fields). Any additional Event fields that the trigger needs to access must be granted as well.</p><p>The system permission “Edit Events” is also required to actually edit Event records, which also grants permission to create and delete events. Event is a special kind of “Activity” object, and the OWD for Activities is either “controlled by parent” or “private”. In the case of “controlled by parent”, Modify All permission would be required on the Account object to edit Account-related Events. In the case of “private”, Activities are only accessible to the user that created them, so the system permission “Modify All Data” would be required to be able to access the Events for all users. There does not exist a “Modify All” permission only for the Event object.</p><p>Fortunately, the License Review object is a regular custom object, so it is possible to grant Create access to the object (which also forcibly grants View access) along with any fields that the system needs to set.</p><h3>User Context Result and Impact</h3><p>In the worst-case scenario, users performing Account address changes require the Modify All Data system permission in order for the behind-the-scenes automations to be performed by the trigger in order to fulfill the business requirements.</p><p>In the best-case scenario, users performing Account address changes require the system permission “Access Activities” and “Edit Events”, which grants access to Events, Tasks, and Email Messages, and users are permitted to not only edit Events, but to create and delete Events, as well as modify a number of fields on both Events and Email Messages. Users also have the ability to View and Create LicenseReview records.</p><p>🙋 Remember Addie Fixer? Previously, Addie was explicitly granted the following permissions necessary to fulfill her job function:</p><ul><li>Object: Account — Modify All object permission</li><li>FLS: Account.Name, Account.RecordType, Account.BillingAddress, Account.ShippingAddress</li><li>Assigned Application: “Data Steward Console”</li><li>Connected App: Data Loader</li><li>System Permission: Lightning Experience User</li></ul><p>To implement the hypothetical business requirements for the behind-the-scenes processing, in order for the trigger to use the User Context approach, the following <em>additional</em> permissions would need to be granted:</p><ul><li>Object: Account — Modify All object permission (to edit Events for all users if Activities are “controlled by parent”; fortunately, Addie already had this permission!)</li><li>Object: LicenseReview — View, Create</li><li>FLS: LicenseReview.* (for the fields modified by the system)</li><li>FLS: Event.* (14 forced fields, plus other fields that need to be modified by the system)</li><li>System Permission: Access Activities</li><li>System Permission: Edit Events</li><li>System Permission: Modify All Data (worse case scenario, if Activities OWD is “private”)</li></ul><p>Through the UI, Addie can continue to perform her job function as usual, and the behind-the-scenes business logic will execute as expected whenever Account addresses are modified.</p><p>However, the “Data Steward Console” application may have been created to support more job functions than just Addie’s, and Addie was previously only able to access the Account object (tab) that her job required. With additional permissions granted to Addie, she may now have access to other objects as well, such as the Events, Tasks, LicenseReviews, and EmailMessages. Of course, one possible solution to mitigate this problem is to create a specialized application for Addie, at the expense of increased administrative and maintenance cost. This may not seem like a big deal in this contrived example where the user’s job function involved a single object, but more real-world examples often involve dozen<em>s</em> of objects adding to the complexity.</p><p>Finally, remember that Addie was granted access to Data Loader as a normal part of her job function and the frequent need for mass updates. Previously, Addie could only modify Account records with Data Loader (or any other API-tool she was granted access to). With the additional object permissions that were granted, she now has the ability to use Data Loader to access Event records, Task records, export Email Messages, and LicenseReview records. And while some of those records were only <em>intended</em> to be created or modified by “the system”, Addie has been granted access to create and modify records <em>directly</em>, bypassing any presumed system control over these actions. One possible solution to mitigate this problem is to remove access to Data Loader and require Addie to make all changes through the UI, but doing so will undoubtedly impact productivity and cost the business money.</p><p>In summary, it was previously possible to provision Addie’s permissions in Salesforce to just the objects, fields, system permission, and tools that were needed by Addie to perform her job duties effectively and productively, nothing “extra” was granted. “Least privileged” or “minimum access” was achieved. However, when the behind-the-scenes automations were implemented and chose to enforce User Context, Addie was forced to be granted additional permissions to additional objects and fields — not because Addie required those permissions as part of the data she was authorized to access or the actions she was hired to perform, but because “the system” required those permissions to be given to the user in order for behind-the-scenes functionality to successfully occur. Addie <em>had</em> to be given access to more data then needed. The permissions granted to Addie go far beyond what would be considered “minimum access”.</p><p>But the implications of the User Context approach do not end there.</p><p>(Continued in <a href="https://medium.com/@feldhacker.chris/how-overuse-of-salesforce-user-context-increases-security-risk-part-2-2a9d69cc3a32">Part 2 — Cascading Impacts</a>)</p><h3>Related</h3><p><a href="https://medium.com/@feldhacker.chris/using-salesforce-system-context-in-itself-is-not-a-privilege-escalation-vulnerability-63abf20c5f74">Using Salesforce System Context In Itself Is Not a Privilege Escalation Vulnerability</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1de2e91ac953" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Salesforce System Context In Itself Is Not a Privilege Escalation Vulnerability]]></title>
            <link>https://medium.com/@feldhacker.chris/using-salesforce-system-context-in-itself-is-not-a-privilege-escalation-vulnerability-63abf20c5f74?source=rss-3c1f555a87ab------2</link>
            <guid isPermaLink="false">https://medium.com/p/63abf20c5f74</guid>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[salesforce-security]]></category>
            <category><![CDATA[salesforce-security-model]]></category>
            <category><![CDATA[salesforce-development]]></category>
            <dc:creator><![CDATA[Chris Feldhacker]]></dc:creator>
            <pubDate>Thu, 18 Jul 2024 22:29:41 GMT</pubDate>
            <atom:updated>2024-07-18T22:29:41.293Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*b1eeOjATJNHa-3Ge" /><figcaption>Photo by <a href="https://unsplash.com/@flyd2069?utm_source=medium&amp;utm_medium=referral">FlyD</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Wikipedia provides an superb definition of <a href="https://en.wikipedia.org/wiki/Privilege_escalation">privilege escalation</a>:</p><blockquote><em>Privilege escalation is the act of exploiting a bug, a design flaw, or a configuration oversight in an operating system or software application to gain elevated access to resources that are normally protected from an application or user. The result is that an application or user with more privileges than intended by the application developer or system administrator can perform unauthorized actions… Privilege escalation means users receive privileges they are not entitled to.</em></blockquote><p>When thinking about privilege escalation, there are some key questions to consider:</p><p>Did the user actually <em>exploit</em> an application vulnerability for the action to be performed? Who is in control of the actions being perform, the user or the system? Is the user able to somehow specify or control the action or the data being access? Are the actions really “unauthorized”, or is the system working as intended?</p><p>If an application is working as intended, and a user isn’t able to exploit the application and trick it into returning data, modify data, or perform some other action that it shouldn’t, then there is no privilege escalation.</p><p>Application “intent” is also an important aspect to clarify. Intent originates from application developers and system administrators through the interpretation and implementation of business requirements in order to deliver expected outcomes. Only Salesforce customers can determine the intent of the customizations they create.</p><h3>Terminology</h3><p>Generally speaking, a Salesforce transaction can operate in one of two modes: “User Context” and “System Context”. Either the permissions explicitly assigned to the user are being enforced, or they are not. Over the years Salesforce has introduced a number of security-related features in Apex and SOQL that impacts a user’s ability to access data. Some solutions take in to consideration record sharing, some don’t. Some respect field-level security (FLS), some don’t. Some respect restriction rules, some don’t. Some solutions cause a transaction to fail with an error, while some cause inaccessible data to be removed from results quietly.</p><p>For the purpose of this discussion, the term “User Context” is used to mean the permissions assigned to the user and what the user has explicit access to are being enforced (either completely or partially), while the term “System Context” is used to mean the user’s explicitly assigned permissions are not enforced. User and System Context in a transaction <em>may</em> be achieved using the SOQL/DML access keywords, but it could also include other Apex security features that are used or combined in ways that achieve a similar result (e.g., “stripInaccessible”). User Context and System Context are better viewed as two polar ends of a permission-enforcement spectrum, with considerable gray in between.</p><p>If user permissions are not being enforced with System Context, then that <em>sounds</em> bad, and the use of System Context must be a privilege escalation vulnerability, right? Not so fast. Did the user <em>exploit</em> something? How is the application <em>intended</em> to behave? Some key pieces are missing from the puzzle.</p><h3>Situation Matters</h3><p>Using System Context in itself is not a privilege escalation vulnerability. It’s not enough to simply search the Apex code base of an org and look for all occurrences of “WITH SYSTEM_MODE”, “as system”, or “without sharing” and conclude “these are all privilege escalation vulnerabilities and must be eliminated”. That’s not accurate. Asserting that the <em>mere use</em> of System Context is a sign of a privilege escalation vulnerability is like asserting the <em>mere use</em> of dynamic SOQL is a sign of a SOQL injection vulnerability. It’s not true. There <em>could</em> be a vulnerability present, or it could be harmless. It depends on whether or not there exists an execution pathway that could allow a user to specify or control the data being accessed, such as input from the user being used to specify object or field names. (There is a name for the scenario when an entity with fewer permissions can trick an entity with greater permissions into misusing its authority on the system, it’s referred to as the “<a href="https://en.wikipedia.org/wiki/Confused_deputy_problem">confused deputy problem</a>”. It is a specific type of privilege escalation.)</p><p>While static SOQL has many benefits and is a great practice to encourage when possible, dynamic SOQL still has its place. Likewise, reminding developers to always keep access controls top-of-mind and to always respect user permissions when returning data to a user or allowing a user to modify data is definitely a great security principle to reinforce. When<em> </em>user permissions <em>do</em> need to be enforced, a variety of Apex/SOQL keywords and utilities can be implemented to achieve that. When user permissions do <em>not</em> need to be enforced, System Context still has its place, too.</p><h3>Good Intentions</h3><p>Suggesting that System Context should never be used is well-intentioned, but it is neither achievable nor realistic. The solution to the confused deputy problem isn’t to banish all deputies, rather the solution is to acknowledge the deputies and make sure they only operate by-the-book (as intended) and won’t be tricked by users into doing something they shouldn’t. System Context has its place, just as dynamic SOQL has its place.</p><p>A transaction might even start off enforcing user permissions and performing access control checks, but the transaction may continue to invoke other code that is designed to perform certain actions irrespective of the user’s assigned permissions. To ensure proper system behavior and prevent over-provisioning of permissions, these actions normally execute using System Context. Intentionally.</p><h3>Separation of Duties</h3><p>An effective investment in energy might be to promote a clear separation between code that operates with user permissions vs System Context, and the classes where the security context <em>switches</em> then become a strong focus for security reviews. Is input from the user being passed to the code operating in System Context and could be used to trick the code into doing something unintended? If any “results” are returned from the code operating in System Context and will be displayed to the user, is data that should be inaccessible to the user being stripped appropriately? A customer org may have a lot of System Context use, but it should be present in the right places and used in the right contexts.</p><p>Keeping a clear separation between the parts of an application that need to operate with different permissions is good security design, and “<a href="https://en.wikipedia.org/wiki/Privilege_separation">privilege separation</a>” is a secure coding technique to implement the principle of least privileges within software. However, on the Salesforce platform, developers cannot achieve <em>literal</em> process-level control and separation. Within an Apex transaction, permission context switching can happen class by class, and at each SOQL query and DML operation. As a result, developers are wise to adopt patterns and conventions for organizing Apex code that can help to make logical privilege separation clear, as well as simplify secure code reviews and vulnerability remediation.</p><h3>How About Broken Access Control? Authorization Bypass? Missing Authorization?</h3><p>No, these are all slight variations on the same vulnerability theme from different angles, but don’t hold up when looking past the labels and performing similar thoughtful analysis. Intent is still the key consideration, followed by whether or not the user is actually exploiting something.</p><p>When applications developers implement business requirements and make deliberate and intentional choices along the permission-enforcement spectrum, that doesn’t mean authorization is “missing”, rather such authorization checks were <em>never intended to be present to begin with</em>. Non-existent authorization checks aren’t being bypassed and aren’t broken, they just aren’t needed.</p><p>If an application is working as intended, and a user isn’t able to exploit the application and trick it into returning data, modify data, or perform some other action that it shouldn’t, then there is no broken access control, no authorization missing or being bypassed, and no privileges being escalated.</p><p>System Context has a rightful place in the code base of a customer Salesforce org.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=63abf20c5f74" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>