A third-party Salesforce code review examines custom code without the assumptions that come from building it. An outside reviewer can question familiar shortcuts and trace how the code behaves for different users and record volumes. This guide explains what an Apex audit finds, how providers perform the review, and what buyers should expect from the report.
TL;DR
A third-party Apex audit checks whether custom code exposes data, fails under load, or creates release risks. Reviewers combine automated scanning with manual checks of access controls, application logic, tests, and integration paths. API version 67.0 also changed default Apex security behavior, so upgrades need permission-focused testing. A useful report identifies confirmed findings, rates their impact, and gives developers specific fixes.
What a Salesforce Code Review Covers
A Salesforce code review is a structured examination of custom code in an org, mainly Apex classes and triggers, along with Visualforce pages, Lightning components, and the automation they interact with. The goal is to find defects before they cause data exposure or failed releases. A third-party review adds an independent view from people who didn’t write the code.
Most reviews cover 5 areas. Security looks at who can see and change data through the code. Performance looks at how the code behaves against platform limits and large data volumes. Design looks at structure, such as trigger patterns and separation of logic. Testing looks at whether tests prove behavior or only produce coverage. Maintainability looks at dead code, hardcoded values, and outdated API versions.
| Area | Typical Questions |
| Security | Does the code respect sharing and field access? Can input change a query? |
| Performance | Will the code stay within limits with 200 records or 2 million? |
| Design | Is trigger logic organized so changes don’t collide? |
| Testing | Do tests assert results, or only run lines? |
| Maintainability | Are API versions current, and are IDs or secrets hardcoded? |
Scope varies by provider and by need. Some reviews cover the whole org. Others focus on a single managed package, a recent release, or a high-risk area such as an Experience Cloud site. Agree on scope in writing before work starts, because a review of 40 classes and a review of 900 classes are very different jobs with very different reports.
Why Orgs Bring In a Third Party
Teams bring in outside reviewers for independence and for timing. Internal code review is valuable, but it has limits that an outside review can fill.
Research on code review explains part of the gap. A study of code review at Microsoft, presented at ICSE 2013, found that finding defects is the main reason developers review code. Yet actual reviews turned out to be less about defects than expected and more about knowledge transfer and team awareness. The authors also found that understanding the code and the change is the core challenge of reviewing. Day-to-day peer review tends to check a change in context. A dedicated audit has the time to read the whole codebase for risk.
Several situations make an outside review especially useful:
· Before a major release or platform upgrade, when the cost of a hidden defect is highest
· After a vendor or contractor hands over code that your team now has to own
· When a security, audit, or compliance team asks for independent evidence about custom code
· When an org has grown for years without a clear owner for code quality
An independent reviewer can give assurance teams another view of the code. The value of that view depends on the reviewer’s technical competence and the evidence behind each finding. A report that reproduces a defect and explains its impact gives internal teams a stronger basis for scheduling fixes.
Know the boundaries before you buy. A code review covers code. Org settings such as profiles, permission sets, and guest user configuration usually need a separate configuration review. Good reviewers flag configuration problems they notice along the way, but a code-focused scope won’t systematically check them. If you need both, say so when you agree on scope.
CRUD, FLS, and Sharing Gaps
Data access gaps can be among the most serious findings in a Salesforce code review. Apex has historically run with more access than the user who triggered it, and code that doesn’t account for that can expose records or fields the user shouldn’t see.
How Apex Access Works Today
For most of the platform’s history, Apex database operations ran in system mode, which ignores the running user’s object permissions and field-level security. Sharing depended on each class’s sharing declaration, and classes without one often ran without sharing. Salesforce’s Apex security guide describes the tools developers use to enforce access, including the with sharing keyword, user mode for database operations, and the stripInaccessible method. Reviewers check whether each class uses those tools where it should.
What Changed in Summer ’26
Summer ’26 changed the defaults. As Salesforce’s Summer ’26 highlights explain, API version 67.0 runs database operations in user mode by default, and classes without an explicit sharing declaration now default to with sharing. The WITH SECURITY_ENFORCED clause also becomes a compiler error at that version. Triggers still run in system mode, but the handler classes they call are affected. Existing code at version 66.0 or earlier keeps the old behavior until someone raises its API version. That makes Apex security reviews more important during upgrades. A class may return fewer records after permissions are enforced, while other permission changes can raise access errors. Code using WITH SECURITY_ENFORCED also won’t compile at API version 67.0; it needs to be reviewed and updated to use WITH USER_MODE where appropriate.
Where Access Gaps Hurt Most
Public-facing sites raise the stakes. In 2023, KrebsOnSecurity reported that many public Salesforce Community sites were leaking private data because guest users had been given access to internal resources. That was a configuration problem. Apex controllers that run without sharing can widen the same kind of exposure, which is why reviewers pay close attention to any class reachable by guest or community users.
Injection and Input Handling
Injection flaws are another important Apex security risk, because they let user input change what code does. One form reviewers check is SOQL injection, where input is concatenated into a dynamic query string. A user who controls part of that string can sometimes widen the query and read records outside the intended filter.
Injection is among the web application security risks listed in the OWASP Top 10, and Salesforce code isn’t exempt. A reviewer looks for dynamic SOQL built with string concatenation, especially where the input comes from a page parameter, a Lightning component, or an API call. The safer patterns use bind variables, which keep input as data. When dynamic field or object names are unavoidable, the reviewer checks that the code validates them against an allowlist or schema describe results.
The difference is easy to see in practice. A search method that adds a user’s text straight into a WHERE clause lets that text carry extra conditions. The same method using a bind variable treats the whole text as a single value to match, whatever it contains. A bind-variable fix may be small when a query has a straightforward structure. More complex dynamic queries need additional validation and regression tests.
Cross-site scripting is the other main input risk. It appears when code writes user-supplied values into a page without proper encoding. Visualforce pages that turn off escaping, and components that insert raw HTML, are common places to look. Lightning Web Components escape output by default, so findings there usually involve code that deliberately bypasses those protections.
A good review also checks the less obvious inputs. Data that arrives from an integration or sits in a record created by a guest user is still untrusted. Code that trusts it because it came from inside the org can be just as vulnerable as code that reads a URL parameter. Reviewers trace where each input comes from before deciding whether the handling is safe, and that tracing is where human review adds the most value over pattern matching.
Governor Limits and Bulkification
Governor limits are the rules that cap what a single Apex transaction can do. Code that ignores them works in testing and fails in production when data volumes rise. Finding those failure points is one of the most practical results of a Salesforce code review.
According to the Apex governor limits documentation, a synchronous transaction can issue up to 100 SOQL queries and 150 DML statements. It also gets 10,000 milliseconds of CPU time. Winter ’27 increased the synchronous heap limit from 6 MB to 10 MB and the asynchronous heap limit from 12 MB to 25 MB, as Salesforce confirms in its Winter ’27 developer guide. The older heap limits still apply to orgs that haven’t received Winter ’27. Every query and update counts against those numbers for the whole transaction, including other triggers and automation that run along the way.
The classic finding is a query or DML statement inside a loop. It works when a user edits 1 record. It can fail when a data load or mass update sends 200 records through the same trigger. Reviewers also look for code that queries the same data more than once and for nested loops over large collections.
Bulkification is the fix. Code collects the records it needs, queries once, works on the collection, and writes the results in as few statements as possible. A reviewer checks every trigger and every method a trigger calls against that pattern. It’s tedious work to do by hand across hundreds of classes, which is why limit risks often survive for years until a large data load exposes them. Salesforce Code Analyzer flags many loop-based queries and DML statements automatically, so reviewers can spend their time judging which ones sit in high-volume paths.
Limits also interact with asynchronous design. Code that moves heavy work to queueable or batch Apex gets more headroom, but it adds its own risks, such as jobs that chain without control. A third-party reviewer looks at whether async processing is used for the right reasons and whether failures are handled and visible.
Trigger Design and Automation Conflicts
Trigger design decides whether changes to an object’s logic stay predictable. Orgs that grow without a pattern often end up with several triggers on the same object, each written by a different team, with no control over which runs first.
Salesforce’s order of execution documentation sets out the sequence the platform follows when a record is saved, including validation rules, before and after triggers, flows, and other automation. When more than 1 trigger exists for the same object and event, the order between them isn’t guaranteed. That makes bugs that appear only in certain conditions hard to reproduce and hard to fix.
Reviewers usually recommend 1 trigger per object that hands work to a handler class. They also check for recursion, where an update in a trigger fires the same trigger again until governor limits are hit. Static flags that stop recursion are common, but crude flags can block legitimate second passes and hide errors.
Mixed automation adds another layer. Many orgs combine Apex triggers with record-triggered flows on the same objects. Each tool may work correctly alone, while together they update the same fields or set off loops. A thorough review maps the automation on high-traffic objects and flags overlaps. That map often turns out to be one of the most useful outputs for admins as well as developers, since it shows the full picture of what happens when a record is saved.
Test Quality Beyond 75% Coverage
Test coverage is a deployment gate, but its threshold depends on how tests are run. For production deployments using RunLocalTests or RunAllTestsInOrg, Salesforce generally requires at least 75% overall org-wide Apex coverage and some coverage for every trigger. Under RunSpecifiedTests, the named tests must cover each deployed class and trigger individually by at least 75%. The Salesforce deployment test-level documentation explains these separate checks. Passing either threshold doesn’t prove that tests check the right behavior. Tests should also assert results under bulk processing and restricted permissions.
An audit may find test classes that meet coverage thresholds but miss these checks. Common problems include:
· Tests that run code but make no assertions, so they pass even when results are wrong
· Tests that use 1 record and never check bulk behavior
· Tests that rely on existing org data instead of creating their own
· Tests that never run as a restricted user, so they can’t prove access controls work
· Large test methods that cover everything at once and hide which behavior failed
The restricted-user gap matters more after the Summer ’26 changes. Salesforce’s own guidance for API version 67.0 recommends adding test scenarios that run as restricted users and assert the correct data visibility before upgrading a class. Tests written only as an admin can’t catch a class that suddenly returns fewer records, or one that returns too many.
Reviewers also check how tests build their data. A shared test data factory makes tests shorter and easier to change, because 1 place creates valid accounts, contacts, and other records. Without one, each test builds records its own way, and a single new required field can break dozens of tests at once.
A third-party Salesforce code review usually samples test classes and rates them against these points. The result often shows that coverage numbers overstate how safe a deployment is. Fixing weak tests takes effort, but it pays back on every future release, since good tests catch regressions before users do.
Secrets, Integrations, and Connected Apps
Integration code is one place credentials and tokens can leak into source. Reviewers look for usernames, passwords, API keys, and endpoint URLs written directly into Apex classes or custom settings that many users can read. Anyone who can view the code or the setting can then reuse those secrets outside Salesforce.
The safer pattern is to store callout endpoints and authentication in named credentials. As the named credentials guide explains, Apex can reference a named credential as the callout endpoint, so the platform handles authentication and the code holds no secrets. Reviewers check each callout for this pattern, along with error handling and any logging that might record sensitive responses.
Integrations also carry risk outside the code itself. In September 2025, the FBI issued a FLASH advisory on 2 criminal groups stealing data from Salesforce instances. One used social engineering to get employees to approve malicious connected apps. The other abused compromised OAuth tokens from a third-party integration. Neither campaign depended on a flaw in Apex, but both show why reviewers ask which integrations call into custom code and with what permissions.
That’s where Apex security meets org configuration. A class exposed as a REST endpoint, or one called by an integration user with broad permissions, can return far more data than intended if its access checks are weak. A good review lists every externally reachable entry point, such as REST resources and invocable methods, and checks each one with the same care as a public web page.
Technical Debt: API Versions, Dead Code, and Hardcoded IDs
Technical debt findings rarely cause an outage on their own. They make every future change slower and riskier, and some carry dates you can’t move.
API versions are the clearest example. Every Apex class and trigger is saved with an API version, and behavior can differ between versions. Salesforce’s versioned behavior changes page lists major Apex changes by version and recommends consolidating a codebase on as few API versions as possible, ideally 1. Reviewers flag spread-out versions and plan the upgrade path, especially across the version 67.0 security change.
Platform API retirement adds a deadline for integrations, separate from the API version saved on an Apex class. According to a Salesforce help article, SOAP, REST, and Bulk API versions 21.0 through 30.0 were retired in Summer ’25. Versions 31.0 through 40.0 are scheduled for deprecation in Summer ’27 and retirement in Summer ’28. These deadlines affect consumers calling those platform API versions. They don’t retire saved Apex classes, triggers, Visualforce pages, or Flows simply because those components use the same version numbers. Reviewers should check integration endpoints separately from Apex versioned behavior.
Other debt findings are smaller but common. Hardcoded record IDs break when code moves between sandboxes and production. Hardcoded profile or user names fail when someone renames them. Dead code, such as classes nobody calls and commented-out blocks, adds noise to every review and every deployment. Duplicate logic copied across classes means a fix in one place leaves the bug alive in another. A Salesforce code review can list these quickly, and removing them makes the next round of work cheaper.
Some debt also hides security risk. Old classes that nobody owns can be the ones still running without sharing, built before the team adopted better patterns. Cleaning them up removes code that would otherwise need its own security fixes.
Automated Scans Versus Manual Review
Automated scanning and manual review find different problems, and a strong Salesforce code review uses both. Tools are fast and consistent across thousands of lines. People understand intent and how the pieces connect.
Salesforce Code Analyzer is Salesforce’s own free scanner for the platform. Salesforce made version 5 generally available in 2025, and its Code Analyzer announcement describes how it brings together engines including PMD for Apex, ESLint for JavaScript, RetireJS, a Regex engine, and a Flow Scanner. It can run from the command line, in VS Code, and in CI/CD pipelines, and it includes rules used in AppExchange security preparation. Teams building packages for AppExchange still go through Salesforce’s own security review, so a third-party audit is preparation for that process and doesn’t replace it.
| Finding Type | Automated Scan | Manual Review |
| Query or DML inside a loop | Usually caught | Confirms real risk and fix |
| Missing sharing declaration | Usually caught | Judges whether the class needs it |
| SOQL injection | Often caught as a pattern | Traces whether input is truly untrusted |
| Business logic errors | Rarely caught | Main source of findings |
| Automation conflicts across triggers and flows | Partly caught | Maps the full save path |
| Weak test assertions | Partly caught | Judges whether tests prove behavior |
The difference comes down to context. A scanner flags every class without a sharing declaration, but only a person can decide whether a given class needs system access for a valid reason. A scanner flags dynamic SOQL, but a person has to trace whether the input can be controlled by a user. Automated results also need triage, since a first scan of a large org can return thousands of findings, many of them low risk.
The practical approach is to run Salesforce Code Analyzer first and use its results to guide manual effort. Reviewers spend their time on the findings that matter and on areas tools can’t judge. Teams can then keep the same scanner in their pipeline after the audit, so new code meets the standard the review set.
How a Third-Party Apex Audit Runs
A well-run Apex audit follows a clear sequence, and knowing it helps you prepare and set expectations. The steps below reflect a common structure, though providers vary in detail.
1. Agree on scope and access. Define which code, packages, and orgs are in scope, and how reviewers will get read access to source and metadata.
2. Gather context. Collect architecture notes, integration lists, known issues, and the business processes the code supports.
3. Run automated scans. Use Salesforce Code Analyzer and similar tools to produce a baseline of pattern-level findings.
4. Triage scan results. Remove false positives and group related findings so manual effort goes where risk is highest.
5. Review manually. Read high-risk classes, triggers, and entry points in full, tracing data access and input handling.
6. Validate findings. Confirm key issues in a sandbox where possible, so the report shows real behavior.
7. Report and walk through. Deliver findings ranked by severity, with fixes, and review them with your team.
Security frameworks support this kind of review. NIST’s Secure Software Development Framework includes reviewing and analyzing code to identify vulnerabilities as part of producing well-secured software. Citing it can help internal teams explain why an independent review belongs in the development process, rather than being a one-off event.
The size of the job depends mostly on scope and code volume, along with how many entry points reach outside the org. A focused review of 1 managed package or a recent release is far smaller than a full org review with years of history. Ask providers to state the number of classes, triggers, and components they plan to read in full, since that number drives both time and cost more than any headline rate.
Preparation shortens the audit. Give reviewers a sandbox that mirrors production, a list of integration users and their permissions, and a contact who can answer questions about business rules. Reviews stall when reviewers wait days for access or have to guess what a process is meant to do.
How to Compare Apex Audit Proposals
Ask each provider to list the exact review scope in its proposal, including classes, triggers, Lightning components, integrations, and whether org configuration is covered. Confirm which code they’ll inspect manually and what will be scanned. A fixed-price quote that covers a narrow sample isn’t comparable to a review of every externally reachable entry point.
The deliverables should include a ranked findings report, evidence for critical issues, file or class locations, recommended fixes, and a walkthrough with developers. Pricing usually depends on code volume, the number of integrations and public entry points, access to a representative sandbox, and the depth of manual verification. Ask who handles remediation, what it costs, and whether a retest of critical and high findings is included.
Before signing, request a sample finding and a written plan for disputed results and follow-up testing.
Reading the Report and Prioritizing Fixes
A useful report ranks findings by risk and explains each one in plain terms, with the location, the impact, and a recommended fix. A report that lists 2,000 scanner findings with no triage isn’t a review, and it’s hard to act on.
Most reports use a severity scale like the one below. Labels vary between providers, but the logic is similar.
| Severity | Example Finding | Typical Response |
| Critical | Guest-reachable class returns records without sharing | Fix before next release |
| High | SOQL injection in a dynamic query from user input | Fix in current sprint |
| Medium | DML inside a loop in a trigger handler | Plan into near-term work |
| Low | Hardcoded record ID in a utility class | Fix during related changes |
Rank fixes by exposure rather than by effort. A small change that closes a guest-user data path is worth more than a large refactor of internal code. Group related fixes, such as all classes that need explicit sharing declarations, so developers make consistent changes in 1 pass.
Ask the reviewers for a rough effort estimate on each high and critical finding. That turns the report into a plan you can schedule, and it shows where a quick fix closes a large risk. Apex security findings usually lead that list, since a short change to a query or a sharing declaration can close a real data path.
Plan a follow-up check. Rerun the automated scan after fixes, and ask reviewers to confirm the critical and high findings are closed. Then add the scanner and its agreed ruleset to your pipeline so the same problems don’t come back. A Salesforce code review has the most value when its standards become part of daily work instead of a document that sits in a folder.
Final Thoughts on Third-Party Apex Audits
A third-party Apex audit helps teams find risks that have become easy to overlook. Ask for a report that separates confirmed security findings from scanner noise, explains the production impact, and assigns a clear follow-up check. Before the next release or API-version upgrade, use that report to prioritize fixes and make the agreed review rules part of your development process.
Frequently Asked Questions
What Is a Salesforce Code Review?
A Salesforce code review is a structured check of custom code in an org, mainly Apex classes and triggers. It looks for security gaps, performance risks, design problems, weak tests, and outdated code before they cause failures or data exposure.
What Does a Third-Party Apex Audit Catch That Internal Review Misses?
Outside reviewers read the whole codebase without knowing why shortcuts were taken. They often find data access gaps, limit risks, automation conflicts, and weak tests that internal reviewers have learned to overlook.
What Are the Most Common Apex Security Findings?
Apex security findings can include classes that skip sharing checks, queries that don’t enforce field access, and SOQL injection in dynamic queries. Reviewers also check for hardcoded credentials and weak protection around externally reachable classes.
How Did Summer ’26 Change Apex Security?
In API version 67.0, Apex database operations run in user mode by default, and classes without a sharing declaration default to with sharing. Code at version 66.0 or earlier keeps the old system mode behavior until its version is raised.
What Are Apex Governor Limits?
Governor limits cap what a single Apex transaction can do. A synchronous transaction can issue up to 100 SOQL queries and 150 DML statements, with 10,000 milliseconds of CPU time. Winter ’27 increased the synchronous heap limit to 10 MB and the asynchronous heap limit to 25 MB. Older orgs retain the previous 6 MB and 12 MB heap limits until they receive the release.
Why Do Queries Inside Loops Cause Problems?
Each query in a loop counts against the transaction limit. Code that works for 1 record can fail when a data load or integration sends 200 records through the same trigger.
Is 75% Test Coverage Enough?
The threshold depends on the test level. For RunLocalTests or RunAllTestsInOrg, production deployments generally require at least 75% org-wide Apex coverage, with some coverage for each trigger. For RunSpecifiedTests, every deployed class and trigger needs at least 75% coverage from those tests. The percentage alone doesn’t prove the tests check the correct results or permissions.
What Is Salesforce Code Analyzer?
Salesforce Code Analyzer is a free, open-source static analysis tool from Salesforce. Version 5 combines engines such as PMD, ESLint, RetireJS, a Regex engine, and a Flow Scanner, and it runs in the CLI, VS Code, and CI/CD pipelines.
Can Automated Scanning Replace Manual Review?
No. Scanners catch pattern-level issues quickly, but they can’t judge business intent or trace whether input is truly untrusted. The most useful audits use scans to guide manual review.
What Is SOQL Injection?
SOQL injection happens when user input is concatenated into a dynamic query. A user who controls part of the query can widen it and read records outside the intended filter. Bind variables prevent most cases.
How Should Integrations Store Credentials?
Integrations should use named credentials for callout endpoints and authentication. Hardcoded usernames, passwords, and API keys in Apex or readable settings can be reused by anyone who sees them.
Why Do API Versions Matter in a Code Review?
Apex behavior can change when a class’s saved API version changes. Separately, Salesforce is deprecating SOAP, REST, and Bulk API versions 31.0 through 40.0 in Summer ’27 and retiring them in Summer ’28. That retirement doesn’t directly apply to saved Apex classes, triggers, Visualforce pages, or Flows.
How Long Does an Apex Audit Take?
It depends on scope, code volume, and how quickly reviewers get access and answers. A review of a single package is much smaller than a full org review, so agree on scope in writing first.
What Should an Audit Report Include?
It should rank findings by severity and give each one a location, an impact, and a recommended fix. It should also separate confirmed issues from scanner noise and suggest a follow-up check.
How Often Should an Org Get a Salesforce Code Review?
Many orgs review before major releases, upgrades, or vendor handovers, and after long periods without a code owner. Running a scanner in the pipeline between reviews keeps standards in place.
