← All posts
· 4 min read ·
SecurityOWASPSalesforceApex

OWASP Top 10 for Salesforce Developers

The OWASP Top 10 doesn't disappear just because you're on Salesforce. Here's how each category manifests in Apex and LWC - and how to fix them.

Dark terminal screen showing security code analysis

As an OWASP member I see the same misconception repeatedly: developers assume the Salesforce platform handles security for them. It handles some of it. The rest is squarely on you.

Here’s how the OWASP Top 10 maps to Salesforce development - with real examples from code reviews.

A01: Broken Access Control

The most common Salesforce manifestation is ignoring sharing rules in Apex. Any class declared without sharing bypasses the org’s record-level security entirely.

// Bad - ignores sharing rules
public without sharing class AccountService {
    public List<Account> getAll() {
        return [SELECT Id, Name FROM Account];
    }
}

// Good - respects the running user's access
public with sharing class AccountService {
    public List<Account> getAll() {
        return [SELECT Id, Name FROM Account];
    }
}

Use inherited sharing on utility classes that are called from both contexts.

A02: Cryptographic Failures

Salesforce Shield Encryption protects data at rest, but it doesn’t protect data in transit within your Apex logic. The classic mistake is logging or passing sensitive field values in plaintext through custom metadata, custom settings, or debug logs.

Never store credentials or tokens in custom settings - use Named Credentials and External Credentials instead. They’re designed for this.

A03: Injection

SOQL injection is the Salesforce equivalent of SQL injection, and it’s everywhere in legacy code:

// Vulnerable - user input injected directly into query
String name = ApexPages.currentPage().getParameters().get('name');
List<Account> accounts = Database.query('SELECT Id FROM Account WHERE Name = \'' + name + '\'');

// Safe - use bind variables always
List<Account> accounts = [SELECT Id FROM Account WHERE Name = :name];

LWC is vulnerable to XSS if you use innerHTML or lwc:dom="manual" with unescaped user content. Use innerText or the lightning-formatted-text component instead.

A04: Insecure Design

This is about architecture, not just code. In Salesforce, the most dangerous insecure design decision is building critical business logic in Flow rather than Apex - not because Flows are inherently insecure, but because they’re harder to code-review, version-control, and test with the same rigour as Apex.

Complex security-sensitive logic belongs in Apex with unit tests. Keep Flows for UI and orchestration.

A05: Security Misconfiguration

Profile and permission set sprawl is the number one security misconfiguration I see. Orgs with hundreds of profiles, most cloned years ago and never audited. Every profile with “Modify All Data” because someone needed it once.

Run the Salesforce Security Health Check regularly and enforce a minimum score in your pipeline.

A06: Vulnerable and Outdated Components

Managed packages. They install code directly into your org with full execution privileges and many orgs never update them. Build a managed package inventory, subscribe to their release notes, and include package version checks in your deployment pipeline.

A07: Identification and Authentication Failures

Two common failures: not enforcing MFA (Salesforce now requires it, but many orgs have exemptions in place from before the mandate), and not auditing connected apps. Every OAuth-connected app is a potential authentication bypass.

Audit your connected apps quarterly. Revoke anything that hasn’t been used in 90 days.

A08: Software and Data Integrity Failures

In Salesforce CI/CD, this means your deployment pipeline must be the only path to production. If a developer can deploy via change set, IDE, or anonymous Apex in production, your integrity guarantees are worthless.

Lock down production with IP restrictions on developer tools and audit trail monitoring.

A09: Security Logging and Monitoring Failures

Salesforce provides Event Monitoring - use it. Track logins from new IPs, bulk data exports, permission changes, and API calls. Feed this into your SIEM.

The minimum you should have: alerts on any permission set assignment in production, any Connected App authorization, and any report export over 10,000 rows.

A10: Server-Side Request Forgery

Apex callouts to external services based on user-supplied URLs are a real SSRF vector. Always validate the URL against an allowlist of approved endpoints - never let a user control where your Apex makes HTTP requests.

// Bad
HttpRequest req = new HttpRequest();
req.setEndpoint(userSuppliedUrl); // Never do this

// Good - validate against allowlist
Set<String> allowedHosts = new Set<String>{'api.partner.com', 'hooks.slack.com'};
URL parsed = new URL(userSuppliedUrl);
if (!allowedHosts.contains(parsed.getHost())) {
    throw new SecurityException('Endpoint not in allowlist');
}

Security on Salesforce is a shared responsibility model. The platform does a lot - but it can’t protect you from your own code.

← All posts