DEV Community

praveenlavu
praveenlavu

Posted on Originally published at praveenlavu.com

AppExchange security review: what it checks

What an AppExchange security review preflight actually checks

The email arrives looking innocent enough. "Congratulations on submitting to the AppExchange Security Review." Then you open the linked documentation and feel it, that specific flavor of dread reserved for large PDFs with multiple appendices.

Every Salesforce ISV has been here. You've built something real. Your customers are waiting. And between you and the listing sits a process that, from the outside, looks like a wall that randomly decides to open or stay shut.

Here's what nobody told me clearly, and what took embarrassingly long to figure out: the review isn't random. It has a structure. It organizes itself around a recognizable set of topic areas, and the day I actually mapped those areas out, labeled them, asked what each one was fundamentally protecting against, the whole thing shifted. It stopped being an intimidating monolith that happened to you and became something you could methodically work through before you ever paid for the real submission. That cognitive shift from "opaque bureaucratic wall" to "organized set of concerns I can address one at a time" is not a small thing. It probably saved me weeks of anxious, unfocused remediation work.

This is that map.

The anatomy of a security review

What the reviewer is fundamentally doing: determining whether your app can be trusted inside someone else's production org. Not trying to break your app, trying to figure out whether your app could inadvertently break their customer's org, leak their data, or reach beyond what any reasonable user authorized.

Every failure pattern across every topic area traces back to the same root. The app assumed too much about what it was allowed to do.

Data access and field-level enforcement

What the reviewer wants to see: every data access operation respects object-level and field-level security as configured in the target org.

This one catches more teams than any other area, and I think I understand why. Developer orgs are permissive by default. You build in an environment where everything works, then ship into real orgs where it won't, where the rep profile has field restrictions, where certain objects are locked down, where the thing you tested as an admin quietly misbehaves for everyone who isn't. The gap between "works in my sandbox" and "works in their production" is exactly this gap. Closes in developer confidence, opens in reviewer findings.

Design-time fix: enforce at the data layer, not as a UI afterthought. Batch jobs aren't exempt from this, and a lot of teams forget that part until it's flagged.

Injection vectors

What the reviewer wants to see: dynamic queries built with bind variables, page output that escapes content before rendering.

The classic trap is the developer who handles the obvious user-input field carefully, then leaves an API parameter unguarded because "only our integration calls that endpoint." The review does not care about your architecture. It cares about the attack surface. Every input that crosses a trust boundary is an input, regardless of who you expect to be sending it.

Design-time fix: treat every input as untrusted at the boundary it enters. That framing is simpler than trying to reason about your caller list.

External integrations and callout configuration

What the reviewer wants to see: remote site settings and trusted URLs scoped to what the app actually needs. Not wildcarded.

The failure mode here is almost always the dev-to-production configuration leak. A remote site setting pointing at a test environment that nobody cleaned up before packaging. I've seen this happen to teams who were otherwise careful, it's not carelessness, it's the accumulation problem. You add something to unblock a build, you move on, it survives every checkpoint between dev org and submission package.

Design-time fix: treat your remote site settings as a documented contract. If you can't explain a specific entry in one sentence, it shouldn't be in the package.

Credential handling

What the reviewer wants to see: credentials in Named Credentials. Not in custom settings, custom metadata, not hardcoded anywhere in the codebase.

The most common failure here isn't ignorance, it's the "we'll fix it before GA" credential that never got moved. Starts as a shortcut during early integration work, survives the entire test cycle, makes it into the package. The road to a failed security review is paved with temporary decisions that became permanent ones.

Design-time fix: one rule about where credentials live, communicated to everyone who might write code that calls an external service. Enforced as culture, not as a last-minute audit sweep.

Lightning component security model

What the reviewer wants to see: components that don't expose Apex controllers more broadly than needed, methods that validate what they accept.

The over-exposure pattern at the Apex layer is more common than it should be. A method that does more than the component needs. Parameters accepted without validation because the component only passes clean values anyway. The framing that breaks this open: for every Apex method reachable from a Lightning component, ask what happens if someone calls it directly. Not through your component, directly. What can they do? That question surfaces a different answer than "the UI only sends valid data."

Design-time fix: scope methods tightly. What the component needs, exactly that and nothing more.

Sharing architecture and visibility

What the reviewer wants to see: Apex that runs in user mode or explicitly justifies running without sharing. No mechanism that lets one user reach another user's records in ways the org model didn't intend.

The with-sharing omission is the classic version of this failure. A class without an explicit sharing declaration inherits whatever context called it. In a complex callstack, that becomes unpredictable fast, and "unpredictable" is not a word you want anywhere near data visibility decisions.

Design-time fix: sharing behavior explicit everywhere. Absence of a declaration isn't neutrality, it's ambiguity. Ambiguity at the data layer is a finding.

Org configuration hygiene

What the reviewer wants to see: minimal footprint with documented intent. Permissions granted because they're required. Automation that runs because it's supposed to.

The failure here is almost always accumulation. A long development cycle produces configuration sprawl, things added to unblock something in sprint four, never revisited, still present in the package submitted eight months later. The reviewer isn't looking for a perfectly minimal configuration. They're looking for evidence that you know why everything in your package is there.

Design-time fix: treat your package manifest as a deliverable that gets reviewed, not just generated.

Where the official docs go quiet

The docs are thorough on the "what." Where they go quiet is relative weight: which failures block certification outright versus which earn a fix-and-resubmit cycle. That knowledge lives in the community, not in the documentation, and it matters because not all findings are equal.

One thing that holds consistently: run the official Security Scanner early. Not as a pre-submission ritual. As a development discipline. The scanner misses things, and finding a class of issue in week two of development costs a fraction of what it costs to find it in week twelve.

The next layer

This map surfaces the shape of the problem. What it doesn't give you is the remediation texture, the part where you have a specific finding in a specific area, what does the fix actually look like, end to end.

That's a different kind of document. The checklist tells you what areas to scan and what patterns signal a problem. The remediation library tells you, given this class of finding, here is the path through it. One describes the problem space. The other describes the solution space.

The review is learnable, and this much holds. But the patterns of failure run deeper than any single pass captures, and the more time you spend in this space, the more you notice the same architectural decisions producing the same classes of findings across completely different products, different teams, different industries.

The preflight is where you start. It's not where this ends.

Top comments (1)

Collapse
 
morphoices profile image
MORPHOICΞS.

A helpful means of distinction here is whether you can pass a security check or understand why it is risky. ~

A checklist may inform you that a pattern requires attention, but its greater value is instructing developers in what the pattern’s exposure means and how the risk propagates.

It seems especially important to provide that kind of rationale in a context where the review is part of a workflow rather than a one-off gate.