Salesforce security audit: a repeatable method for consultancies
A Salesforce security audit for a client is skilled work done with weak tools. The consultant knows what to look for: who holds Modify All Data, which classes a guest user can call, which connected app still has a refresh token from a vendor that left two years ago. But the method often lives in a spreadsheet and in the memory of whoever ran the last engagement. Two consultants auditing two orgs check different things, and the client cannot compare this year's report with last year's.
A repeatable method fixes that. The same scope, the same access, the same checks in the same order, and a report the client can hold you to. This post sets out the method we see work for Salesforce partners and consultancies, and where Vulkro for Salesforce fits into each step.
What should a Salesforce security audit cover?
Agree the scope in writing before anyone logs in. A useful default has four parts:
- Source. The client's repository or a metadata retrieve: Apex, Lightning components, Visualforce, Flows, and the metadata that grants access (profiles, permission sets, sharing settings, connected apps).
- The live org. Production, and the sandboxes that matter, as they actually are: users, assignments, sessions, MFA, login history, OAuth tokens, installed packages, Health Check settings. Most of this exists in no repository.
- Public surface. Every Experience Cloud and Salesforce site, and what a guest user can reach through it.
- Integrations. Connected apps, External Client Apps, Named Credentials and the integration users behind them.
Say just as clearly what is out of scope. A configuration and code audit is not a penetration test, does not read business records, and does not certify the org secure. Write that into the statement of work, so nobody reads more into the final report than it says.
The reason to insist on the live org: the incidents that have hit Salesforce customers recently were configuration problems, not platform flaws. The FBI's September 2025 flash alert described attackers abusing connected apps and stolen OAuth tokens. In March 2026 Salesforce attributed a scanning campaign against public sites to customer-configured guest user settings. A source-only audit sees neither.
How do you get read-only access to a client org?
Never ask for an administrator's password, and never use a personal admin account. Ask the client to create a dedicated user with the permissions the audit needs and nothing that writes. For the vulkro-sf org commands that is API Enabled and View Setup and Configuration, plus View Event Log Files for the event monitoring checks.
Vulkro for Salesforce reads the org through the consultant's own Salesforce CLI login. It never handles Salesforce credentials: the OAuth token stays in the sf CLI's store, the analysis runs on the consultant's machine, and nothing is sent to Vulkro. Every read is a query or a metadata retrieve. A few checks count records with SELECT COUNT(), and no business record is read.
sf org login web --alias client-prod
vulkro-sf org status --target-org client-prod
When the engagement ends, the client revokes the CLI session in Setup as they would for any sf login.
A read the audit user cannot make is reported as not covered, never as a clean result.
Day one: the baseline
Run everything once, at the start, before you change anything or advise anyone to. The baseline is what lets you prove at the end what improved.
# Source, with live org facts fused into the attack graph
vulkro-sf scan ./force-app --org client-prod --format json > baseline.json
# Live org posture, as one report
vulkro-sf org report --target-org client-prod -O posture-day1.html
# Focused audits
vulkro-sf org effective-perms --target-org client-prod
vulkro-sf org oauth-risk --target-org client-prod
vulkro-sf exposure ./force-app --target-org client-prod
org effective-perms shows what users really hold through profiles, permission sets and groups. org oauth-risk rates every connected app and External Client App, lists who holds "Use Any API Client" and "Approve Uninstalled Connected Apps", and matches login history and app names against the published indicators of the 2025 Salesforce OAuth campaigns (a match is a reason to investigate, not proof of a breach). exposure reports what an unauthenticated visitor can reach, site by site.
If you have the client's repository, tag the commit you started from. Every later change can then be gated against it.
How do you turn findings into an executive summary?
A list of 300 findings is not a summary. Executives need to know how someone could get to their data, and how likely that is.
That is what an attack path gives you. Each vulkro-sf scan joins who can reach the code (guest, community member, internal user), the door they come through (an Aura or LWC endpoint, Apex REST, Visualforce, a Flow), the grant that lets them in, the access mode the code runs in, and the data it touches. Every step cites a file and line, and a Critical finding is always explained by a path from a person to the data. With --org, the live org adjusts each path: a path whose grant nobody holds is lowered a step, and one whose grant is widely held, or whose guest user owns records, is raised.
Write the executive summary as three to five of those paths, in plain words:
An unauthenticated visitor to the partner portal can read the email and phone number of every Contact, through an Apex method that runs without sharing and is granted to the site's guest profile.
The detail behind each path stays in the body of the report for the client's engineers.
Evidence the client and their auditors can use
Clients often hand your report to an auditor, and screenshots do not survive that. Evidence does:
- Every finding cites the file and line, or the setting and the record id, so it can be checked independently.
- Coverage is explicit. Most org audits accept
--format json-report, which carries the run's read coverage (partial, truncated, unavailable), so a clean section can be told apart from one the audit could not read. - Compliance mapping when asked for.
vulkro-sf compliance report --frameworkmaps findings to SOX, PCI, HIPAA or GDPR control areas.vulkro-sf compliance attestrecords a SHA-256 attestation over a delivered file, with who signed it off, so the client can later confirm the report has not been altered.
Re-test: how do you show what was fixed?
At the end of the engagement, or after the client's team has worked through the findings, run the same commands again and compare with day one. Net new against net fixed is the honest measure of an engagement. The baselines guide describes the source side: gate changes against the tagged starting commit with --gate-vs, then compare a final full scan with the first.
For engagements that continue month to month, Vulkro Cloud does the re-test on a schedule. Each client gets their own workspace, each org is scanned through an External Client App the client owns, read-only, and every scan is compared with the last. Why Salesforce org security needs scheduled scans explains why a one-off audit goes stale.
Handing over the report
The deliverable should be a file the client keeps, not a login to your tooling.
vulkro-sf org reportwrites a self-contained HTML or Markdown posture report of the live org.- For an ISV client preparing a managed package,
vulkro-sf appexchange-report --prepared-for "Client" --prepared-by "Your firm" -o readiness.htmlproduces the AgentExchange readiness report with your client and your firm named on the cover. What fails the AgentExchange Security Review covers what it checks. - Across several orgs,
vulkro-sf portfolio dashboardrenders one self-contained HTML risk dashboard from per-org scan results, grouping the same finding across production, sandbox and dev. The local console (vulkro-sf serve) groups projects and orgs under a named client and exports one client-ready report per client. - In Vulkro Cloud, the Executive Report and evidence packs come as PDFs, and can be emailed monthly or quarterly.
Salesforce security audit checklist
- Written scope: source, live org, public sites, integrations, and what is out of scope.
- A dedicated read-only audit user, revoked at the end.
- A day-one baseline of source and org, kept unchanged.
- An executive summary written as attack paths, not counts.
- Every finding with a file and line or a setting, and explicit coverage.
- A re-test against the baseline, reported as net new and net fixed.
- A handover the client keeps.
Where to see it
Salesforce security reviews for client orgs shows how a consultancy runs one Vulkro Cloud workspace per client. The live org setup docs list every org audit and the permissions each needs.
To run the method on your next engagement, get started.
Frequently asked questions
What is included in a Salesforce security audit?
A thorough one covers the code and metadata in source, the live org's users, permissions, sessions, settings and integrations, every public site and what a guest user can reach, and the connected apps and integration users. It should state what it does not cover, such as penetration testing.
What access does a consultant need for a Salesforce security audit?
A dedicated, read-only user is enough for most checks: API Enabled and View Setup and Configuration, plus View Event Log Files for event monitoring. Never use an administrator's personal account, and have the client revoke the access when the engagement ends.
How is a security audit different from Salesforce Health Check?
Health Check scores the org's security settings against a baseline. An audit also covers who holds which permissions, code and metadata, guest access, connected apps and OAuth tokens, and how those combine into paths to data. Health Check is one input to an audit, not a replacement for it.
How often should a client org be audited?
A full audit at least once a year and after major changes, with scheduled scans in between. Orgs change through Setup every week, so a point-in-time report starts going out of date the day it is delivered.
