When security calls and says "shut this user down," what you do in the next ten minutes matters. This guide walks through the contain‑first actions — freezing, profile changes, permission set removal — and the longer‑term hygiene that keeps a compromise from turning into a breach.
Why user‑level controls are the front line
Every recent high‑profile Salesforce incident — Salesloft Drift, Gainsight, the ShinyHunters vishing wave — eventually traces back to a user identity that should have had less power than it did. OAuth tokens, integration users, and over‑provisioned employees are the same problem in different costumes: too much access, attached to credentials someone else now controls.
You will not always be the one who detects the compromise. You will, however, be the one a security analyst pings on Slack at 4:47pm saying "can you shut down this user, now?" The rest of this post is what to do when that ping arrives, and what to put in place beforehand so the answer is "already contained."
The three immediate containment actions
There is no single right answer for what to do with a compromised user — it depends on whether you need to preserve evidence, keep a license, or fully revoke access. These are the three actions you should know cold.
1) Freeze the user
Freezing is almost always the right first move. It is fast, reversible, and preserves everything an investigator needs.
Setup → Users → Users → (select user) → Freeze
What freezing does:
- Immediately blocks the user from logging in
- Revokes active sessions and OAuth tokens tied to that user
- Leaves the license, record ownership, sharing, and audit history intact
- Lets you unfreeze in one click once the incident is closed
What freezing does not do:
- Free the user's license — the seat is still occupied
- Remove permission set assignments — power is still attached, just dormant
- Stop background processes the user owns from running (scheduled Apex, etc.)
Use freeze when you need to stop the bleeding without destroying evidence. It is the digital equivalent of "step away from the keyboard."
2) Change the user's profile to read‑only
If you cannot freeze (for example, the user is needed for an investigation, or a service account that other automations depend on), neuter the profile instead.
A safer pattern than the stock "Read Only" profile is a dedicated "Quarantine" custom profile you create in advance: cloned from Minimum Access, no API Enabled, no export permissions, no Modify All / View All anything, no login on weekends, IP‑restricted to your office or VPN range. Switch the compromised user to that profile and you have effectively locked them in a padded room while keeping the account technically alive.
Why a custom quarantine profile beats the stock Read Only profile:
- You control exactly what stays enabled (CSV export is the obvious one to strip)
- IP and login hour restrictions can be tighter than the org default
- You can keep the user's record ownership and reports intact for handoff
- You avoid licensing edge cases — Read Only is a separate license type with its own quirks
3) Strip the user's permission sets
In modern, well‑structured orgs, the profile is the floor and permission sets are where the dangerous power lives. Removing permission set assignments is often the most surgical containment action you can take.
Setup → Users → Users → (select user) → Permission Set Assignments → Remove
Prioritize removing, in this order:
- Anything granting API Enabled
- Anything granting Modify All Data, View All Data, or object‑level Modify All / View All
- Anything granting Export Reports, Manage Data Integrations, or Author Apex
- Anything granting access to sensitive objects (PII, financial, HR)
- Everything else
If you have permission set groups, removing a single group can revoke a dozen capabilities at once — which is exactly why grouping by job function is worth the upfront effort.
Freeze vs. deactivate vs. read‑only — choosing the right action
| Action | When to use | Reversible? | Frees license? | Preserves ownership? |
|---|---|---|---|---|
| Freeze | First response, evidence preservation, uncertainty | Yes (instant) | No | Yes |
| Quarantine profile + strip permission sets | User still needs limited access; investigation underway | Yes | No | Yes |
| Deactivate | Confirmed malicious insider, terminated employee, retired integration user | Yes (reassignment required) | Yes | Re‑assignment needed |
| Delete | Almost never — Salesforce does not truly delete users | N/A | N/A | N/A |
Default to freeze first, then make a deliberate choice within the hour about whether to escalate to deactivation. Deactivating immediately can complicate forensic review — schedule jobs the user owns will fail, reports will break, and you lose the ability to see what they were last doing inside the UI.
Don't forget the connected pieces
Containing the user object alone is not enough. While the user is frozen, also:
- Reset the password and force a security question reset
- Revoke OAuth tokens for the user under
Setup → Connected Apps OAuth Usage - End active sessions under
Setup → Session Management - Re‑enroll MFA so any attacker‑registered authenticator is invalidated
- Check Login History for the last 30 days — note IPs, geographies, user agents
- Check Setup Audit Trail — has the user changed permission sets, profiles, or sharing rules recently?
- Check report exports and Data Loader runs — did data already leave?
If you have Salesforce Shield Event Monitoring, this is what it was bought for. Pull API event logs and report export events for the user across the suspected window.
Strategic hygiene: making the next breach smaller
Containment is faster when your org was built with containment in mind. The practices below are not new — they are just universally under‑implemented.
Stop using standard profiles
The single highest‑leverage change you can make is to move every user off the stock standard profiles (System Administrator, Standard User, Marketing User, etc.) and onto custom profiles cloned from Minimum Access — Salesforce.
Standard profiles cannot be meaningfully edited. They were designed as starting points, not destinations. Building on top of Minimum Access flips the model from "remove what's dangerous" to "add what's necessary" — which is the actual definition of least privilege.
The pattern:
- Clone Minimum Access — Salesforce into a custom profile named for the role (e.g.
Sales Rep — Custom) - Grant only the object permissions truly required by every member of that role
- Layer everything else through permission sets, not profile edits
This pattern also makes deactivation cleaner: if a profile only grants a baseline, you can deactivate or freeze a user with confidence that you know the full scope of what they had access to — because it is enumerated in their permission set assignments, not buried in profile edits.
Use permission sets and permission set groups for everything else
Profiles answer "who is this user?" Permission sets answer "what can they do today?" The second question changes all the time; the first does not.
Concretely:
- One user → one profile (forced by Salesforce) → describes the baseline role
- One user → many permission sets → describe the layered capabilities
- Permission set groups → bundle the common combinations (e.g.
PSG_Sales_Managerincludes the rep permission set, the forecast permission set, and the manager‑only reports permission set)
Naming convention matters more than people think. A consistent prefix scheme (PS_, PSG_, MUTE_) makes audit and containment dramatically easier. If you can grep a clear name for every dangerous capability, you can revoke it under pressure.
Make API Enabled its own permission set
This is the single highest‑ROI permission set you can create. Most users — sales, service, marketing, exec — never need API access. They use the UI. Yet on many orgs, API Enabled rides along on the profile because someone needed it once.
Create a dedicated permission set, name it explicitly, and assign it deliberately:
Permission Set: PS_API_Access_Integration
System Permissions:
- API Enabled: ✓
Assignment Policy:
- Integration users only
- Reviewed quarterly
- Documented business justification per user
The same pattern applies to:
- PS_Bulk_API_Access — separate from regular API
- PS_Data_Export — for Data Loader / report export
- PS_Modify_All_Data — almost no one should have this
- PS_View_All_Data — almost no one should have this either
When a compromise happens, you remove one or two permission sets and the user loses every channel for bulk data exfiltration.
Enforce MFA — and phishing‑resistant MFA for admins
Salesforce now requires MFA for all UI logins, and starting in mid‑2026 is enforcing phishing‑resistant MFA (FIDO2 security keys, platform authenticators) for any user with admin‑adjacent permissions: Modify All Data, View All Data, Customize Application, Author Apex, or the System Administrator profile.
The practical implication: SMS and TOTP are no longer enough for anyone with elevated rights. Hand out hardware security keys to administrators, and consider doing the same for integration owners and finance/HR users who handle sensitive data.
A few related practices that compound:
- SSO with a strong IdP, plus MFA enforced at the IdP, simplifies the entire flow and gives you one place to kill sessions
- Session Settings → Enforce login IP ranges on every request — without this, IP restrictions only apply at login time
- High Assurance Sessions for sensitive screens (Setup, exports, reports above a threshold)
- Trusted IP ranges to avoid MFA prompts only from controlled networks, not as a security control by themselves
Restrict by IP, time, and network
For any account that should be predictable — service accounts, integration users, admins — restrict the surface area aggressively at the profile level:
- Login IP Ranges — only your office, VPN, or known integration egress IPs
- Login Hours — service accounts often don't need to log in between 11pm and 5am
- Session timeouts — shorter for high‑privilege users
- Re‑login on suspicious changes — re‑auth before changing email, password, or MFA settings
A compromised credential that can only be used from one IP range, during business hours, with a hardware key, is a compromised credential the attacker cannot use.
Treat integration users like radioactive material
The Gainsight and Salesloft Drift incidents both abused integration identities. Every integration user should be:
- On its own dedicated profile cloned from Minimum Access
- Assigned only the API permission set
- IP‑restricted to the integration partner's documented egress range
- Granted object/field access via a permission set named after the integration
- Reviewed every quarter — does this integration still exist?
- Monitored for unusual call volume, user agents, and geographies
Never use a System Administrator account as an integration user. Never share integration credentials between two systems. Never let an integration user have UI login if it doesn't need one.
A response runbook you can lift
Write this down somewhere everyone can find it before you need it.
T+0 (first 5 minutes)
- Freeze the user
- Reset their password
- End active sessions
- Revoke OAuth tokens for that user
T+15 (first quarter hour)
- Move user to the Quarantine custom profile
- Remove all permission set assignments
- Pull Login History and Setup Audit Trail for the last 30 days
- Note the incident in your tracking system
T+60 (first hour)
- Decide: keep frozen, deactivate, or restore with reduced permissions
- If integration user: rotate any associated client secrets and connected app credentials
- Check for data export events (reports, Data Loader, Bulk API) in the window of compromise
- Notify stakeholders per your incident response plan
T+24 hours
- Full review of what the user touched — records modified, accessed, exported
- Determine notification obligations (legal, customers, regulators)
- Post‑mortem: how did the credential get compromised, and what permission set made the blast radius bigger than it had to be?
Key takeaways
-
Freeze first, ask second. Freezing is reversible, instant, and preserves evidence. It is almost always the right opening move.
-
Profiles describe identity; permission sets describe power. When containing a user, the permission sets are usually what you want to remove.
-
Build a Quarantine profile in advance. Custom, locked‑down, ready to switch to. You don't want to be cloning profiles during an active incident.
-
API Enabled does not belong on a profile. Put it on a permission set, assign deliberately, review often.
-
Custom profiles cloned from Minimum Access are the foundation everything else depends on. Standard profiles are starting points, not destinations.
-
Phishing‑resistant MFA is the new baseline for admin‑adjacent users. Hand out security keys before Salesforce makes you.
-
Integration users are the most dangerous users in your org. Treat them accordingly — dedicated profile, single permission set, IP‑restricted, monitored.
Additional resources
- Protecting Salesforce Data After an Identity Compromise
- Salesforce Security Advisories
- Salesforce Multi‑Factor Authentication FAQ
- Salesforce Network Access and Profile‑Based IP Restrictions
- Salesforce Security Roadmap 2026
The best incident response is the one where containment is boring because the org was built to contain. Freeze the user, strip the permission sets, breathe out — and then go fix whatever in your access model made the call necessary in the first place.