Pass AppExchange Security Review the first time.
Vulkro for Salesforce reads what your team built on Salesforce, plus the live org, the way a Security Review reads them, on your own machine. It tells you whether the package is ready before you pay for the review slot, and what the org looks like after the deploy. Nothing is uploaded.
Ten minutes on your own machine. Free needs no account; the 14-day trial of the full product needs no card.
$ vulkro-sf presubmit ./force-app # example output AppExchange pre-submission gates --------------------------------------- [FAIL] no SOQL or runtime injection (3) [FAIL] CRUD and FLS enforced (5) [PASS] no secrets in source or metadata [PASS] sharing declared [PASS] no cleartext HTTP endpoints [PASS] modern cryptography [FAIL] Lightning component security (1) [PASS] Visualforce security [PASS] least-privilege metadata [ -- ] Flow security not evaluated exit 1 # a failing gate blocks the pipeline
A failed round is counted in weeks, not in bugs.
The scanners the review process runs execute inside Salesforce's pipeline, after you have already submitted. Three facts about that round, stated carefully.
About half, the figure partners cite
Salesforce publishes no first-pass failure rate. The number partners quote most often for first submissions is about half, and it is an industry estimate, not an official one.
A paid listing pays per attempt
On a paid listing, every submission is another fee. The most common reason for a failed round is missing CRUD or field-level checks, which is exactly what a scan finds first.
Two to three weeks of turnaround
Each round takes two to three weeks. A ten-minute check on your own machine, before you submit, is the cheapest one you will ever run.
Six Salesforce surfaces, read as one project.
Code, components, Flow, the metadata that wires them, and the running org. A value the browser controls is followed from a Lightning component into Apex and on to the query or the record write it reaches.
Apex
Every way in (@AuraEnabled, @HttpPost, @InvocableMethod, @RemoteAction), the queries, record writes and outbound calls each one reaches, the sharing declaration, and whether a permission check stands in the way.
Lightning Web Components
Public properties, URL reads, wire adapters and imported Apex methods, with a value the browser controls followed across the boundary into Apex.
Aura and Visualforce
Components, controllers and helpers, the server actions they call, and the places a record value lands in markup the user can influence.
Flow
Flow logic, subflow links and Apex actions, plus the guest-user paths that turned public sites into data leaks at other companies.
The metadata that wires it
Profiles, permission sets, sharing rules, connected apps, named and external credentials, remote sites, CORS and CSP entries, and Agentforce topics and actions.
The live org
Permissions, MFA coverage, session settings, sharing rules, connected apps, login history and Trust status, read through your own Salesforce login. Settings only, never your records.
Know the answer before you pay for the review slot.
Six requirement categories, each scored pass, gap or not evaluated, against the real failure causes. Not evaluated is never counted as a pass. The same report exists as a file you can hand to a reviewer or a client.
9 blocking gaps across 3 of 6 requirement categories. 1 category not evaluated.
- Package
- Acme Billing Suite
- Version
- 3.4.0
- Basis
- checklist pinned 2026-Q2
| Requirement category | Criterion | Status | Blocking | Highest | First citation |
|---|---|---|---|---|---|
| Secure coding and injection defence | SF-ASRR-001 | gap | 3 | CRIT | force-app/main/default/classes/InvoiceController.cls:214 builds SOQL from a page parameter. |
| Sensitive data protection and cryptography | SF-ASRR-002 | pass | 0 | none | No key, token or credential literal in package source or metadata. |
| Sharing and access control | SF-ASRR-003 | gap | 5 | HIGH | force-app/main/default/classes/QuoteService.cls:88 writes without a CRUD or FLS check. |
| Client-side and UI security | SF-ASRR-004 | gap | 1 | MED | force-app/main/default/lwc/quoteViewer/quoteViewer.js:63 assigns a record value to innerHTML. |
| Integrations and external callouts | SF-ASRR-005 | pass | 0 | none | Every callout routes through a Named Credential over TLS. |
| Least-privilege metadata and automation | SF-ASRR-006 | not evaluated | 0 | unknown | No profile or permission set metadata was retrieved in this scan, so nothing was scored. |
Readiness assessment against the published AppExchange Security Review requirements. It is not an official review outcome: Salesforce Product Security decides that. A category no detector covered on this scan reads not evaluated, does not block, and still needs checking by hand.
Source says what you deployed. The org says what is true now.
A permission set edited in Setup, a connected app approved last week, a session policy relaxed for one integration: none of it is in your repository. The org audit reads the running org through your own login, settings only, and never your records.
| Check | Rule | Status | Severity | Evidence |
|---|---|---|---|---|
| MFA enforcementvulkro-sf org mfa | SF-MFA-001 | gap | CRIT | 2 of 61 active users can log in with a password alone (no MFA, no SSO). |
| Guest user accessvulkro-sf org guest-live | SF-GUEST-LIVE-001 | gap | HIGH | Guest profile for site partner-portal holds Read on Contact and Opportunity. |
| Connected appsvulkro-sf org connected-apps | SF-CONNECTED-APP-004 | gap | HIGH | Billing Sync uses an http:// callback URL and requests refresh_token scope. |
| Permission set assignmentsvulkro-sf org perms | SF-PERM-ASSIGN-001 | gap | MED | 4 users hold Modify All Data outside the admin permission set group. |
| Sandbox refreshvulkro-sf org sandbox-refresh-lag | SF-SANDBOX-002 | gap | MED | Full sandbox uat last refreshed 214 days ago; production data has drifted. |
| Session settingsvulkro-sf org session | SF-SESSION-002 | pass | none | Timeout 30 min, sessions locked to login IP, clickjack protection on. |
| Sharing rulesvulkro-sf org sharing-rules | SF-SHARING-002 | pass | none | No criteria-based rule grants Read/Write to All Internal Users. |
| Login historyvulkro-sf org login-history | SF-LOGIN-HISTORY-002 | pass | none | No successful login from an unseen country in the last 30 days. |
| Trust statusvulkro-sf org trust-status | SF-PKG-VERIFY-001 | pass | none | Instance NA142 has no open incident or maintenance on Salesforce Trust. |
| Event monitoringvulkro-sf org event-monitoring | SF-EVENT-MON-001 | not evaluated | unknown | Event Monitoring is not licensed in this org, so there is no event stream to read. |
| Health check scorevulkro-sf org health-check | SF-HEALTH-CHECK-001 | not evaluated | unknown | API returned 403 for this user. Grant View Setup and Configuration, then re-run. |
Not evaluated is not a pass. Two checks could not run against this org, so two answers are still unknown.
An agent action is a new way into your data.
Every action an Agentforce agent can take is followed to what it touches: record data, or a call that leaves the org. Actions bound to classes that skip sharing, bundles with no least-privilege guard, and agents grounded on untrusted text are flagged, in the authoring source and in the compiled metadata.
- edge resolved from action metadata
- reaches record data
- call that leaves the org
The Billing support topic binds four actions. Two of them read Invoice, Account and Contact records, and one reaches a callout that leaves the org carrying values the agent controls. The graph is resolved from the topic and action metadata in the checkout: no action is invoked.
| Action | Type | Reaches | Finding | Declared at |
|---|---|---|---|---|
| LookupInvoice | apex | Invoice__c, Contact | MEDVULK-4090 | force-app/main/default/classes/InvoiceController.cls:118 |
| SummarizeAccount | apex | Account, Contact | no finding | force-app/main/default/classes/AccountSummary.cls:64 |
| SendPaymentLink | flow | callout:Partner_Billing | HIGHVULK-4102 | force-app/main/default/flows/Send_Payment_Link.flow-meta.xml |
| SearchKnowledge | standard | nothing outside the topic | no finding | force-app/main/default/genAiPlugins/Billing_Support.genAiPlugin-meta.xml |
Also in the box, all on your machine.
The parts that turn a scan into a working day: what a guest can see, what a change will break, a fix you can trust, and the places you already work.
Guest exposure report
One report of everything a guest user can reach on a public site: pages, Apex, Flows and records, with the setting that opened each one.
Change safety before deploy
Where a component is used, what breaks if it goes, what a change touches, and how big a deploy is, scored. Static and best-effort, and it says so.
Fixes with the detector as the judge
An optional local AI model drafts an Apex fix; it is applied only when a fresh check agrees the problem is gone. The model never decides what is true.
In your editor and your AI assistant
The Salesforce edition of the extension underlines problems in Apex, Lightning and Flow files as you type. A skill and an MCP server let Claude Code and other assistants ask for a check.
The console, plain words
Every problem in a dashboard on your machine, with a view of what changed since the last check and an impact view showing how far a problem reaches across the org.
Evidence and inventory
A package inventory of your managed and unlocked packages with known vulnerabilities, compliance mapping for SOC 2, PCI, HIPAA and GDPR, and a shareable org posture report.
What it is not.
Stated here rather than discovered on day two.
Your customer records
Never read. No Accounts, Opportunities, Leads, Cases, custom-object rows or attachments. The org audit reads settings and definitions through your own login, which you can revoke at any time.
A penetration test
A review of code, metadata and settings that names the weak spot and cites the file and the line. It does not attack a running org or prove an exploit.
A guarantee that a check ran
Every surface can report a third state: a category with no coverage, or an org check your user could not run, reads not evaluated. It is never counted as a pass, and the row says what to grant.
Everything outside Salesforce
Apex, Lightning, Flow, Visualforce, metadata and the org. Your Node, Python, Go, Java, C or PHP services are Vulkro, the code scanner, on the same engine.