Skip to main content

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.json at the root and a force-app/ (or similar) source tree underneath.
  • A retrieved metadata folder: the output of sf project retrieve start --target-org ... or a legacy MDAPI package.xml retrieval.
  • 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 to vulkro-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 on 1.
  • 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 sf CLI to enable the posture and packages detectors.
  • CI/CD integration: wire vulkro-sf scan into GitHub Actions, GitLab CI, or Bitbucket Pipelines.