AppExchange Security Review readiness report
Salesforce ISVs shipping managed packages through AppExchange pass a Security Review run by Salesforce's Product Security team. The review is structured around a published checklist. The single largest cause of rejection is CRUD/FLS gaps; the rest of the long tail (SOQL injection, secrets in source, Visualforce XSS, over-privileged profiles, broad OAuth scopes, named credentials in cleartext) is predictable and statically detectable.
vulkro sf-appexchange-report is the offline pre-submission self
check. Point it at a Salesforce DX or legacy MDAPI project, and it
groups Vulkro's Salesforce findings by the published checklist
sections and renders a single self-contained HTML report rated
PASS / FAIL / NOT EVALUATED per section. The report header pins the
checklist version date so the result is reproducible: a report you
generate today will look the same a year from now, even if the
published checklist changes in between.
Quickstart
vulkro sf-appexchange-report . # render to stdout
vulkro sf-appexchange-report . -o appexchange.html # write to file
Open the resulting HTML in any browser. The browser's File - Save as PDF gives you the PDF deliverable to attach to your submission package.
The default path is the current directory. The directory should
contain sfdx-project.json (SFDX) or package.xml (legacy MDAPI).
Exit codes
0- every covered checklist section passed (zero findings on every section, and at least one section had detector coverage).1- at least one section is FAIL (or the install is on the Free tier).2- argument error or internal failure (missing path, parse error, IO error, internal crash).
Wire into CI as a pre-submission gate:
vulkro sf-appexchange-report ./my-app -o report.html || exit $?
Report layout
- Header: project name, scan timestamp, pinned checklist version string, source URL for the canonical published checklist, and a verdict pill (READY when every section is PASS, GAPS FOUND otherwise).
- Coverage note: a callout reminding the reader that the report is a readiness indicator, not a guarantee, and listing the review categories Vulkro does not cover (penetration test results, org-shape configuration, authentication flows that need a live org to verify, the non-static parts of secure development lifecycle documentation).
- Summary strip: pass / fail / not-evaluated counts, total mapped findings, and the count of other Vulkro findings the scan produced that did not map to a checklist section (so nothing the scanner emitted is silently dropped from the report).
- One row per checklist section: each row carries
- the section title and a one-line description,
- the list of Vulkro rule IDs that cover the section,
- a PASS / FAIL / NOT EVALUATED status pill, and
- a per-finding table (file, line, severity, rule, message) when the section is FAIL.
Checklist sections
The report tracks 10 sections drawn from the public AppExchange Security Review categorisation as of 2026-Q2:
| Section | Vulkro rule coverage |
|---|---|
| Code Quality and Best Practices | apex_soql_injection, apex_unsafe_deserialize, apex_open_redirect, sf_visualforce (dynamic iframe URL) |
| Object and Field Permissions (CRUD / FLS) | apex_crud_fls, apex_crud_fls (per-method gap), apex_idor, apex_mass_assignment, sf_flow (system-mode DML), sf_visualforce (controller exposes request param) |
| Sensitive Data Storage and Logging | apex_secrets, apex_hardcoded_ids, apex_callout_creds, sf_lwc (real-provider API key), sf_lwc (credential-shaped identifier), sf_lwc (credential in browser storage), sf_metadata (named-credential anonymous principal carrying a secret), sf_metadata (connected-app consumerSecret in metadata), sf_metadata (connected-app consumerKey in metadata) |
| Cryptography | apex_weak_crypto |
| Sharing and Visibility (with / without sharing) | apex_runas_misuse, apex_without_sharing, sf_flow (SystemMode context) |
| Lightning Component Security (LWC + Aura) | sf_lwc (XSS surface), sf_lwc (dangerous JS primitive), plus the credential-shape rules above |
| Visualforce Security | sf_visualforce (escape=false), sf_visualforce (script merge), sf_visualforce (dynamic script load), sf_visualforce (dynamic iframe URL), sf_visualforce (controller exposes request param) |
| Profiles, Permission Sets, Named Credentials, Connected Apps | sf_metadata (over-privileged profile/permset), sf_metadata (named-credential password), sf_metadata (named-credential cleartext), sf_metadata (named-credential merge fields in body), sf_metadata (named-credential anonymous principal carrying a secret), sf_metadata (connected-app Full OAuth scope), sf_metadata (connected-app callbackUrl cleartext), sf_metadata (connected-app consumerSecret in metadata), sf_metadata (connected-app consumerKey in metadata) |
| External Integrations and Callouts | apex_callout_creds, sf_metadata (named-credential password), sf_metadata (named-credential cleartext), sf_metadata (named-credential merge fields in body), sf_metadata (connected-app callbackUrl cleartext) |
| Flow Security | sf_flow (hardcoded ID), sf_flow (system-mode DML), sf_flow (SystemMode context) |
The checklist label in the rendered report always matches the public Partner Community section name verbatim. If Salesforce updates the checklist categorisation, the pinned version string in the report header changes and a new mapping is published.
Sample output
<header class="cover">
<div class="cover-l">
<div class="brand">vulkro - Salesforce</div>
<h1>AppExchange Security Review readiness</h1>
<div class="dim">Project: <strong>my-managed-package</strong></div>
<div class="dim small">Scanned: 2026-05-25T14:33:10Z</div>
<div class="dim small">Checklist pin: AppExchange Security Review checklist mapping v0.1.0 (based on public sections as of 2026-Q2)</div>
</div>
<div class="cover-r">
<div class="verdict crit">GAPS FOUND</div>
</div>
</header>
Caveats
- This report is a static-analysis readiness indicator, not a guarantee of acceptance. Salesforce's Product Security team makes the final review determination.
- Sections marked NOT EVALUATED still require manual review.
- The mapping table is pinned to a specific date (the
CHECKLIST_VERSIONconstant insrc/security/appexchange_mapping.rs). Verify against the latest published checklist before relying on the report for a submission. Open an issue at [email protected] if the published checklist has changed and we have not yet updated the mapping.
Related
vulkro scan .for the full Vulkro scan output without the AppExchange-checklist grouping.vulkro compliance --profile owasp-asvsfor an OWASP-checklist view of the same findings.- The published AppExchange Security Review checklist itself: https://partners.salesforce.com/partner_program/security_review/