If you plan to list your app on the AppExchange, the Salesforce Security Review is mandatory. Treat it like a production‑grade security assessment, not a checkbox.
Why the review exists
Salesforce protects customers by ensuring AppExchange apps meet a baseline for secure design, implementation, and operations. The review looks beyond code into your SDLC: threat modeling, dependency hygiene, secrets handling, incident response, and how you run production.
How the process works
At a high level, you will:
- Prepare artifacts (below) and complete the security questionnaire.
- Submit a managed package (or integration) build.
- Provide credentials and test data.
- Undergo automated scanning and manual testing.
- Remediate findings (if any) and resubmit.
Typical timelines range from 2–6 weeks depending on complexity and remediation cycles.
What Salesforce examines
- Architecture and data flow diagrams
- Authentication and authorization (Salesforce user context, OAuth flows, session handling)
- CRUD/FLS/Sharing enforcement for Apex/soql/sosl
- Input validation and output encoding
- Storage and transmission of sensitive data (PII, secrets, tokens)
- Platform configuration (Remote Site Settings, CSP, named credentials)
- Dependency and third‑party risk
- Operational security (logging, monitoring, incident response)
Common failure categories (and how to avoid them)
1) Missing CRUD/FLS checks
Always enforce CRUD/FLS and sharing when accessing SObjects.
// BAD: direct SOQL without sharing/FLS
List<Account> accts = [SELECT Id, Name, AnnualRevenue FROM Account];
// GOOD: with sharing, strip fields you can't access, and check FLS
public with sharing class AccountController {
@AuraEnabled(cacheable=true)
public static List<Account> listAccounts() {
Schema.DescribeSObjectResult d = Account.SObjectType.getDescribe();
if (!d.isAccessible()) {
throw new System.NoAccessException();
}
// query only fields caller can read
List<String> fields = new List<String>();
if (Account.Name.getDescribe().isAccessible()) fields.add('Name');
String soql = 'SELECT ' + String.join(fields, ',') + ' FROM Account';
return Database.query(soql);
}
}2) Insecure remote calls
Use Named Credentials, enforce TLS, validate hosts, and least privilege scopes for OAuth.
3) Secrets in code or logs
Never hardcode secrets. Store secrets in a secure store and redact sensitive values from logs.
4) Unvalidated input and XSS
Validate all inputs and encode outputs. Prefer platform encoders and parameterized SOQL.
5) Incomplete SDLC controls
Demonstrate CI/CD, code review, SAST/DAST, dependency scanning, and documented incident response.
What to include in your submission
- System context and data flow diagrams
- Threat model summary and key mitigations
- Authentication/authorization model (user roles, scopes, Sharing rules)
- Secure coding practices (CRUD/FLS policy, input/output handling)
- Third‑party/dependency inventory and patch policy
- Logging and monitoring approach (PII redaction, retention)
- Incident response plan (triage, comms, timelines)
- Pen test/SAST/DAST results and remediation notes
Preparation checklist
- Apex runs
with sharingwhere required - CRUD/FLS enforced on all data access paths
- Named Credentials and CSP configured; outbound hosts approved
- Secrets stored outside source, rotated, and access‑controlled
- Input validated; output encoded; no dynamic SOQL without sanitization
- Dependencies scanned; high/critical issues resolved
- Logs omit secrets/PII; alerts wired to responders
- Security docs complete and consistent with the app behavior
- Run a pre‑submission internal review against Salesforce's checklist