VS Code, Cursor, and Windsurf extension
The Vulkro IDE extension publishes to the VS Code, Cursor, and Windsurf marketplaces from a single source tree. It wraps both binaries:
vulkro(the general-purpose scanner) for non-Salesforce workspaces.vulkro-sf(the Salesforce-specific scanner) for SFDX projects.
Workspace auto-detection picks the right one. The rest of this page covers the SFDX side: installation, the binary-path override, per-file vs whole-workspace scans, inline findings in Salesforce file types, the "explain finding" hover, and the live-org command-palette integration.
Installation
Install from your IDE's marketplace; the extension ID is the same across all three:
| IDE | Marketplace |
|---|---|
| VS Code | Marketplace -> search Vulkro -> install |
| Cursor | same VS Code listing (Cursor consumes the VS Code marketplace by default) |
| Windsurf | same VS Code listing (Windsurf consumes the VS Code marketplace by default) |
The extension is a thin shell over the CLI binaries: it does not
re-implement detection logic. Findings come from vulkro or
vulkro-sf exactly as the CLI emits them. Closed-source detectors
stay closed-source; the extension is the UI surface, not a second
implementation.
Workspace auto-detection
When you open a folder, the extension runs a short heuristic against the workspace root:
sfdx-project.jsonpresent -> SFDX project, usevulkro-sf.force-app/orsrc/with*.cls,*.trigger,*.page,*.cmp,*.lwccontent -> SFDX project, usevulkro-sf.- Otherwise -> generic project, use
vulkro.
In a multi-root workspace each root is classified independently; you can have an SFDX folder and a Node.js folder open in the same window and the extension picks the right binary per file.
The binary-path override
The extension expects vulkro and vulkro-sf on PATH. Override the
location via VS Code settings if you installed to a custom directory:
// .vscode/settings.json (or User Settings)
{
// Path to the vulkro binary. Default: vulkro (resolved against PATH).
"vulkro.binaryPath": "/usr/local/bin/vulkro",
// Path to the vulkro-sf binary. Default: vulkro-sf (resolved against PATH).
"vulkro.sfBinaryPath": "/usr/local/bin/vulkro-sf",
// Minimum confidence level to surface findings. Mirrors the CLI flag.
// Default: medium
"vulkro.minConfidence": "high",
// Run on save (per-file scan) in addition to the on-demand command.
"vulkro.scanOnSave": true
}
The two binary-path settings are independent: you can run a custom
vulkro-sf build (a local feature branch) while keeping the released
vulkro for non-Salesforce folders. Useful for engineers iterating on
the Salesforce module.
Per-file scan vs whole-workspace scan
The extension exposes both shapes through the command palette:
Vulkro: Scan current file-> runs the binary against the single file you are editing. Subsecond latency on the typical.clsfile. The default keybinding iscmd+shift+v cmd+shift+f(macOS) orctrl+shift+v ctrl+shift+f(other).Vulkro: Scan workspace-> runs against the workspace root. Slower but reports the cross-file detections (multiple triggers per object, the ForcedLeak two-pass walk, the AppExchange-readiness rollup). Default keybindingcmd+shift+v cmd+shift+w.
Setting vulkro.scanOnSave: true runs the per-file scan automatically
on save; that is the recommended shape during development. The
workspace scan is the right thing to invoke before opening a pull
request.
Inline findings
Findings render as VS Code diagnostics: red, yellow, or blue squiggles under the exact range, with the rule message in the hover and the finding in the Problems panel.
Every Salesforce-relevant file type carries inline findings:
- Apex (
.cls,.trigger) -> CRUD/FLS, sharing, SOQL injection, IDOR, mass-assignment, crypto, hardcoded secrets,System.debugof sensitive vars, anti-patterns (SOQL in loop,DML in loop, hardcoded IDs, etc.). - LWC (
.js,.html,.cssunderlwc/) -> DOM XSS, postMessage missing origin,wire-to-innerHTMLtaint. - Aura (
.cmp,.controller.js,.helper.jsunderaura/) ->aura:unescapedHtmlwith user input, Aura action CSRF. - Visualforce (
.page,.component) ->escape="false"on user content, external<apex:includeScript>over HTTP, stack-trace disclosure,PageReferenceuntrusted concatenation. - Flow XML (
.flow-meta.xml) -> system-context DML, hardcoded record IDs, guest-context flows. - Profile XML (
.profile-meta.xml) -> guest-user object exposure, over-privilege,viewAllRecords. - PermissionSet / PermissionSetGroup XML -> aggregation risk.
- Metadata XML (
.connectedApp-meta.xml,.namedCredential-meta.xml,.remoteSite-meta.xml,.corsWhitelistOrigin-meta.xml,.cspTrustedSite-meta.xml,.workflow-meta.xml,.securitySettings-meta.xml, etc.) -> posture findings. - GenAi metadata (
.genAiFunction-meta.xml,.genAiPlanner-meta.xml,.genAiPromptTemplate-meta.xml) -> ForcedLeak class-bypass, agent surface findings.
The severity-to-squiggle-colour map matches VS Code defaults: Critical
and High render as Error, Medium as Warning, Low as Information.
The "explain finding" hover
Hover any squiggle to see the rule ID, the one-line finding, the
short remediation, and an Explain link. Clicking Explain opens
a side-panel view rendered from vulkro-sf explain <RULE-ID>: the
same long-form explanation the CLI emits, displayed without leaving
the IDE.
The explain content covers:
- What the rule looks for, in plain language.
- The specific Salesforce safe-app standard it maps to (AppExchange Top-20 #N, PMD Apex rule X, Well-Architected dimension Y).
- A safe pattern, with a code snippet.
- The unsafe pattern, with a code snippet.
- The 2025-26 breach class (if applicable) the rule defends against.
The same body is available at the CLI:
vulkro-sf explain SF-AGENTFORCE-002 prints the identical text.
Salesforce CLI integration
The extension reads sf org list on startup and on the
Vulkro: Refresh org list command. Authenticated orgs show up in
the command palette under:
Vulkro: Live org status (pick org)->vulkro-sf org status --target-org <alias>Vulkro: Live org perms (pick org)->vulkro-sf org perms --target-org <alias>Vulkro: Live org packages (pick org)->vulkro-sf org packages --target-org <alias>
The alias picker is the same list sf org list produces. The
extension does not store the token, does not implement its own OAuth
flow, and does not shell out to anything but sf for the credential
side; see the sf CLI handoff for the full call
shape.
If sf is not on PATH, the org commands grey out in the palette and
the extension shows the install instruction for your platform.
Quiet-mode and the SARIF view
For users who prefer a once-per-PR rollup over inline squiggles:
- Set
vulkro.scanOnSave: falseand rely onVulkro: Scan workspaceinvoked manually before opening a PR. - Use
Vulkro: Show SARIF reportto open the most recent scan result as a single-pane SARIF view (the same file the CI pipeline uploads to GitHub Code Scanning / GitLab Security Dashboard).
The SARIF view groups findings by rule and severity, with click-to-jump into the source range. It is the right view for triaging the workspace scan before opening a pull request.
Where to go next
- The sf CLI handoff: what happens when the extension fires a live-org command.
- Methodology: the rule taxonomy the inline findings map to.
- CI/CD integration: the matching pre-merge gate so IDE findings cannot ship through a PR uncaught.