- Navigate Salesforce's security assessment policies and penetration testing rules of engagement.
- Distinguish between customer-responsible layers (e.g., custom code, sharing rules) and platform-responsible layers.
- Formulate a compliant penetration testing plan that isolates approved targets and avoids restricted systems.
- Master vulnerability assessment techniques for custom Apex controllers, Visualforce pages, and Lightning Web Components.
- Implement robust remediations for high-risk findings, including SOQL injection and privilege escalation.
- Structure formal security assessment documentation to satisfy audit requirements and leadership expectations.
1. Rules of Engagement: The Salesforce Security Assessment Agreement
In an era of sophisticated cyber threats, proactive security testing is a non-negotiable requirement for enterprise applications. Penetration testing—the practice of simulating real-world cyberattacks against a system to discover vulnerabilities—is a critical component of secure application lifecycle management. However, executing a penetration test against a cloud platform like Salesforce is fundamentally different from testing on-premise infrastructure. Because Salesforce is a multi-tenant environment, a poorly planned automated scan or a distributed attack can degrade system performance for thousands of unrelated organisations or violate federal laws. To perform tests safely and legally, architects and security teams must strictly adhere to Salesforce's Rules of Engagement and its formal Security Assessment Agreement.
Historically, Salesforce required customers to submit a detailed notification form and request explicit authorization weeks before executing any penetration test. Today, the process has been modernized. Under the current Security Assessment Agreement, customers are granted pre-authorisation to execute standard, non-disruptive penetration tests and vulnerability assessments without notifying Salesforce in advance, provided they adhere strictly to specific guidelines. The rules of engagement define clear boundaries on what activities are permitted and what is strictly prohibited:
- Prohibited Actions: Under no circumstances may a customer execute a Distributed Denial of Service (DDoS) attack, attempt a physical security breach of Salesforce data centres, execute social engineering campaigns against Salesforce employees, or perform cross-org penetration testing that targets shared database hosts or other customer tenants.
- Restricted Tools: High-bandwidth automated vulnerability scanners (such as Nessus, Qualys, or Burp Suite Intruder) must be throttled to prevent resource starvation. Scanners must never target standard Salesforce shared endpoints (like
login.salesforce.com) and should only target the customer's specific My Domain subdomain or community URL. - Testing Hours and Scope: Testing must be restricted exclusively to the customer's own tenant and assets, isolating custom interfaces, public Experience Cloud sites, and integrated API endpoints.
Tech leaders must ensure that external security vendors hired to perform penetration tests are fully educated on these rules of engagement. Violating these terms can result in immediate termination of Salesforce sessions, temporary suspension of the Salesforce instance, or legal action for breach of contract.
2. The Salesforce Shared Responsibility Security Model
To plan a successful and compliant penetration test, architects must understand the Salesforce Shared Responsibility Security Model. In a cloud SaaS environment, security is a shared mandate divided between the platform provider and the customer. Security teams often waste significant time and budget trying to test infrastructure components that are the exclusive responsibility of Salesforce, while ignoring massive security loopholes in their own custom code and configuration layers.
The Shared Responsibility Model establishes a clear demarcation line between the platform's infrastructure and the customer's custom implementation:
- Platform-Responsible Security (Security of the Cloud): Salesforce is responsible for securing the underlying physical infrastructure, host operating systems, hypervisors, physical storage arrays, database engines, multi-tenant isolation barriers, and global network routing. Penetration testers should assume that these systems are highly secure and compliant with standard frameworks (such as ISO 27001, SOC 2, and PCI-DSS) and should not waste effort testing them.
- Customer-Responsible Security (Security in the Cloud): The customer is responsible for the configuration of their specific Salesforce instance. This includes user profile access controls, permission set architecture, field-level security, record-level sharing rules, custom Apex code, Visualforce and Lightning Web Components (LWC), Connected App settings, integration endpoints, and database security settings.
The vast majority of security breaches in Salesforce instances originate from customer misconfigurations or vulnerable custom code. A penetration test should therefore focus its entire scope on the customer-responsible layers. Testers should evaluate whether a standard user can escalate their privileges, whether guest users can access private objects via Experience Cloud sites, or whether dynamic SOQL queries in custom Apex classes are vulnerable to injection attacks.
3. Preparing and Structuring the Penetration Testing Environment
A critical operational rule that architects must enforce is that penetration testing must never be executed directly in a live production environment. Executing automated vulnerability scanners or simulating malicious attacks against production data can corrupt operational records, trigger thousands of erroneous automated emails to real customers, deplete API request allocations, and cause service disruptions. To ensure safety and validity, tests must be conducted within a dedicated, isolated sandbox environment.
To prepare a sandbox for a penetration test, architects must establish a deliberate, multi-step environment provisioning process:
- Provisioning the Sandbox: Create a newly refreshed Full Sandbox. A Full Sandbox is highly recommended because it mirrors the production data volume, custom metadata, dynamic integrations, and sharing architectures exactly, ensuring that the vulnerability tests yield realistic, actionable results.
- Obfuscating Customer Data: Newly refreshed sandboxes copy all production PII. Before handing access to the security testers, administrators must execute Salesforce Data Mask to sanitise all customer names, emails, and phone numbers. This ensures that testers work with simulated datasets, maintaining compliance with data privacy mandates.
- Configuring Test Accounts: Provision specific test accounts representing different security personas (e.g., Guest User, Standard Employee, Integration User, System Administrator). This allows testers to perform context-aware privilege escalation tests.
- Whitelisting Tester IPs: Add the security testing team's static IP ranges to the sandbox's Trusted IP Ranges. This prevents Salesforce's automated DDoS-prevention systems or IP restriction limits from blocking the testers, allowing the assessment to proceed smoothly.
By establishing these isolation boundaries, organisations can execute deep, rigorous vulnerability assessments without risking the stability or confidentiality of their active production business operations.
4. Common Vulnerabilities in Custom Apex and Lightning Components
When security vendors execute penetration tests against Salesforce instances, they target custom customisations. While Salesforce's declarative platform is highly secure out of the box, custom code written in Apex or Javascript (LWC) can easily bypass standard security perimeters if developers are not trained in secure coding standards. The most common critical vulnerabilities identified during Salesforce penetration tests include SOQL Injection, Cross-Site Scripting (XSS), and Privilege Escalation due to incorrect sharing configurations.
SOQL Injection: Occurs when user-supplied input is concatenated directly into a dynamic SOQL query string without sanitisation. This allows an attacker to manipulate the query's logic, bypassing database security boundaries to retrieve unauthorized records, delete records, or extract metadata. The following dynamic Apex snippet demonstrates a highly vulnerable dynamic SOQL query:
// CRITICAL VULNERABILITY: SOQL Injection via String Concatenation
public List searchContacts(String userInput) {
// Dynamic query vulnerable to injection
String query = 'SELECT Id, Name, Email FROM Contact WHERE Name LIKE '%' + userInput + '%'';
return Database.query(query);
}
If an attacker inputs `test%' OR Name LIKE '%`, the query is evaluated as `Name LIKE '%test%' OR Name LIKE '%'`, returning all contacts in the database, regardless of sharing rules. To prevent this, dynamic queries must always utilise bind variables or input sanitisation.
Privilege Escalation (Without Sharing): In Apex, classes execute in the "system context" by default, meaning they bypass the running user's CRUD/FLS and sharing rules. If a developer declares a class using the without sharing keyword, the class has unrestricted access to the database. If this class exposes data to an public Visualforce page or LWC, an unauthenticated guest user can escalate their privileges, querying records they should never see. Penetration testers actively look for public-facing guest profiles to exploit these loose sharing declarations, making strict sharing enforcement a primary security focus.
To identify these custom code vulnerabilities before a formal penetration test, development teams must integrate static analysis tools into their deployment pipelines. The industry standard for Apex static analysis is PMD, which runs an extensive ruleset specifically designed for Salesforce security. PMD checks for rules like ApexSharingViolations (identifying classes missing sharing declarations) and ApexBadAPICheck (detecting risky API calls or dynamic DML). When PMD detects a violation, it generates a warning that blocks the continuous integration (CI/CD) pipeline. Developers should never bypass these warnings using suppressions (such as @SuppressWarnings('PMD.ApexSharingViolations')) without formal architectural review and sign-off. Enforcing PMD rules guarantees that the vast majority of common code vulnerabilities are remediated during development, allowing the penetration test to focus on complex, context-aware logical exploits rather than simple coding mistakes.
5. Advanced Remediation and Secure Coding Design Patterns
Remediating high-risk findings identified during a penetration test requires a systematic transition to secure coding design patterns. Architects must establish strict Apex review checklists, ensuring that developers utilise modern Salesforce features designed to enforce security boundaries programmatically at the database layer.
To eliminate SOQL injection, developers should default to static SOQL queries. Static SOQL natively protects against injection because the compiler treats all user inputs as bind variables rather than executable database code. If dynamic SOQL is absolutely mandatory (for instance, when building complex search filters with dynamic field lists), input must be sanitised using String.escapeSingleQuotes() or bind variables. The following Apex code demonstrates the three secure remediation options to correct the vulnerable dynamic query:
public class SecureContactSearchController {
// Remediation Option 1: Standard Static SOQL with Bind Variables (Highly Recommended)
public List searchContactsStatic(String userInput) {
String searchPattern = '%' + userInput + '%';
// Native bind variables are immune to SOQL injection
return [SELECT Id, Name, Email FROM Contact WHERE Name LIKE :searchPattern WITH USER_MODE];
}
// Remediation Option 2: Dynamic SOQL with Bind Variables
public List searchContactsDynamicBind(String userInput) {
String searchPattern = '%' + userInput + '%';
String query = 'SELECT Id, Name, Email FROM Contact WHERE Name LIKE :searchPattern';
// Dynamic queries utilizing local bind variables are secure
return Database.query(query);
}
// Remediation Option 3: Dynamic SOQL with Single Quote Escaping (Fallback)
public List searchContactsDynamicEscape(String userInput) {
// Escape single quotes to prevent injection attacks
String escapedInput = String.escapeSingleQuotes(userInput);
String query = 'SELECT Id, Name, Email FROM Contact WHERE Name LIKE '%' + escapedInput + '%'';
return Database.query(query);
}
}
To address privilege escalation and enforce CRUD/FLS, developers must declare Apex classes using the with sharing or inherited sharing keywords. Furthermore, for SOQL queries, developers should append the WITH USER_MODE database clause (introduced in recent releases). WITH USER_MODE forces the query engine to evaluate both sharing rules and field-level security permissions for the running user, throwing a standard exception if the user attempts to query a field or object they lack permission to access. For DML operations, architects should deploy the Security.stripInaccessible() method, which programmatically strips out fields from sObject lists that the running user is not authorised to create or update, maintaining airtight security compliance across all custom interfaces.
Architects must understand the granular mechanics of Security.stripInaccessible() to leverage it effectively. This method evaluates the running user's FLS and CRUD permissions for a specified access type—either AccessType.READABLE, AccessType.CREATABLE, or AccessType.UPDATABLE. It returns a SObjectAccessDecision object containing a sanitised list of sObjects with all unauthorised fields removed, as well as a list of fields that were stripped. Crucially, when handling nested lookup relationships or child subqueries (e.g., querying Contacts as a subquery of Accounts), the method recursively inspects the entire object graph, stripping unauthorized child fields automatically. This makes it an invaluable utility for secure API endpoints, as it prevents accidental field leakage in complex JSON payloads. For DML operations, checking the stripped fields list allows the code to throw a descriptive, custom exception back to the client application, ensuring transparent and secure transaction handling.
Key Takeaways
- Adhere strictly to Salesforce's Rules of Engagement and Security Assessment Agreement when coordinating penetration testing.
- Focus penetration testing efforts exclusively on customer-responsible layers, such as Apex code, sharing models, and custom interfaces.
- Never execute vulnerability assessments or automated scanning against live production instances; always utilise an isolated Sandbox.
- Eliminate dynamic SOQL injection vulnerabilities by defaulting to static SOQL queries or sanitising dynamic inputs.
- Enforce database security boundaries programmatically in Apex using
with sharing,WITH USER_MODE, andSecurity.stripInaccessible(). - Automate code reviews and deploy static analysis tools (like PMD) to detect and remediate vulnerabilities early in the development lifecycle.
Checkpoint: Test Your Understanding
Question 1: According to Salesforce's rules of engagement, which of the following activities is strictly prohibited during a customer's security assessment?
Question 2: What is the safest way to prevent SOQL injection vulnerabilities in dynamic Apex queries that rely on user-supplied inputs?
Question 3: Which clause should be appended to a SOQL query to force the execution engine to evaluate both sharing rules and field-level security for the running user?
Discussion & Feedback