Your first scan
This page is for someone who has just finished Install vulkro-sf and wants to see findings on a real Salesforce codebase in under a minute. The artifact you produce here is a first set of findings on disk: severity counts in the terminal, plus an optional SARIF / JSON / HTML file to feed into a code-review tool or CI gate.
What you need
vulkro-sf scans Salesforce source code on disk. It does not need a
live org for the first scan; the org connector is optional and covered
separately in Live-org setup.
The scanner expects one of these as input:
- An SFDX project: a directory with an
sfdx-project.jsonat the root and aforce-app/(or similar) source tree underneath. - A retrieved metadata folder: the output of
sf project retrieve start --target-org ...or a legacy MDAPIpackage.xmlretrieval. - Any directory containing Apex (
.cls,.trigger), LWC (.js,.html), Aura (.cmp), Visualforce (.page,.component), Flow (.flow-meta.xml), or Salesforce metadata XML.
A typical SFDX layout looks like this:
my-package/
├── sfdx-project.json
├── force-app/
│ └── main/
│ └── default/
│ ├── classes/
│ ├── lwc/
│ ├── flows/
│ ├── objects/
│ └── profiles/
└── ...
The scanner walks the project root, identifies the Salesforce-relevant files, and runs the detector set against them.
The first command
vulkro-sf scan ./force-app
That is the entire command for a first scan. Point it at either the
project root or the force-app/ directory; both work. The scanner
auto-detects the project shape.
What you see
The default output is plain text grouped by severity. A finished scan prints a summary line, then the findings, then exits:
Vulkro for Salesforce 0.5.2
Scanning ./force-app ...
Findings: 12 (Critical: 1, High: 4, Medium: 6, Low: 1)
[CRITICAL] sf_metadata::auth_provider_hardcoded_consumer_secret
force-app/main/default/authProviders/Slack.authprovider-meta.xml:14
Hardcoded consumerSecret in metadata. Move to Protected Custom
Metadata or External Credential.
[HIGH] apex_crud_fls::missing_fls_on_dml
force-app/main/default/classes/LeadController.cls:42
DML insert without CRUD/FLS enforcement. Use
Database.insert(record, AccessLevel.USER_MODE) or
insert as user record;
...
Each finding carries:
- A severity label (Critical, High, Medium, Low).
- A rule ID in the form
module::check_name. Pass that ID tovulkro-sf explain <id>for the long-form rationale (sources, fix, AppExchange-checklist mapping). - A file path and line number.
- A short message stating the failure and the recommended fix.
Exit codes
vulkro-sf scan follows the standard Vulkro exit-code contract:
0: scan completed and no findings were reported.1: scan completed and findings were reported. Wire CI to fail the build on1.2: error (bad arguments, IO failure, project not detected, internal crash). The message printed on stderr says what to fix.
In a CI gate the common pattern is vulkro-sf scan ./force-app || exit $?: any non-zero code halts the build, and 1 versus 2 lets
downstream steps distinguish findings from infrastructure problems.
Choosing an output format
The --format flag picks the output shape:
vulkro-sf scan ./force-app --format text # default
vulkro-sf scan ./force-app --format sarif -o findings.sarif
vulkro-sf scan ./force-app --format json -o findings.json
vulkro-sf scan ./force-app --format html -o findings.html
- text (default): scannable terminal output, grouped by severity.
- sarif: SARIF 2.1.0. Upload to GitHub Code Scanning, GitLab Vulnerability Report, or any SARIF-aware tool. The format every downstream pipeline understands.
- json: machine-readable Vulkro-native JSON. Use this when you want every field the scanner produces (confidence score, OWASP mapping, AppExchange section, breach-class label) and SARIF would flatten that detail.
- html: self-contained single-file HTML. Open in any browser. Useful for sharing one report with a non-technical reviewer.
Use -o <file> to write to a file. Without -o the formatted output
goes to stdout, which is the right shape for piping into another tool.
Tightening (or loosening) what fires
Confidence threshold
Every finding carries a confidence score. The --min-confidence flag
filters anything below the threshold:
vulkro-sf scan ./force-app --min-confidence high # high only
vulkro-sf scan ./force-app --min-confidence medium # high + medium (default)
vulkro-sf scan ./force-app --min-confidence low # everything
Start strict (high) on a new codebase to surface the obvious findings
without noise, then walk the threshold down as you fix things.
Category filter
The --category flag narrows the scan to one of the five pillars:
vulkro-sf scan ./force-app --category code # Apex / LWC / Aura / VF / Flow
vulkro-sf scan ./force-app --category posture # SecuritySettings / sharing
vulkro-sf scan ./force-app --category identity # Profiles / PermSets
vulkro-sf scan ./force-app --category thirdparty # Connected Apps / Named Credentials
vulkro-sf scan ./force-app --category ai # Agentforce / GenAI
Pass the flag multiple times to combine pillars:
vulkro-sf scan ./force-app --category code --category identity
A scan with no --category flag runs every pillar. The narrowed scan
is faster and is the right shape when one workstream owns one pillar
(for example, a security review focused only on guest-user exposure
runs with --category identity).
Where to go next
- Methodology: the master reference for what a safe Salesforce app should be and how every Vulkro detector traces back to a published standard.
- AppExchange readiness report: turn the same findings into the Security Review pre-submission HTML artifact.
- Live-org setup: connect to a live org via
the
sfCLI to enable the posture and packages detectors. - CI/CD integration: wire
vulkro-sf scaninto GitHub Actions, GitLab CI, or Bitbucket Pipelines.