vulkro scan --include-eslint
PRO-T-W-2: ESLint wrapper for Salesforce LWC and Aura. This page covers
the --include-eslint flag on vulkro scan, the bundled ruleset, the
binary discovery rules, and how the wrapper's findings show up in
Vulkro output.
What it does
When you pass --include-eslint, Vulkro:
- Runs the native scan (Apex, Visualforce, Flow, metadata, LWC, Aura, plus every cross-language rule that applies to your project).
- Shells out to a host-installed ESLint with a curated security-only
config, scanning
force-app/main/default/lwc/andforce-app/main/default/aura/. - Parses ESLint's JSON output, maps each message into Vulkro's
SecurityFindingshape, and merges the result into the same findings list. - Returns the merged set to every downstream sink: the CLI table, the
JSON / SARIF / NDJSON / JUnit / CSV formatters, the AppExchange
readiness report,
--fail-on,--gate, the.vulkro-baseline.jsondiff, and so on.
The wrapper makes Vulkro a drop-in replacement for the
sfdx-scanner step that runs ESLint over LWC and Aura.
Quick start
# One-time install of ESLint and the Salesforce plugins
npm install -g eslint @salesforce/eslint-plugin-lwc @salesforce/eslint-plugin-aura
# Pass --include-eslint to opt in
vulkro scan ./my-managed-package --include-eslint
If eslint is not on $PATH but npx is, Vulkro falls back to
npx eslint automatically. To pin a specific binary, set the env var:
VULKRO_ESLINT_BIN=/opt/sfdx/node_modules/.bin/eslint vulkro scan . --include-eslint
Curated ruleset
The wrapper does not load whatever ESLint config the project happens
to ship; it bundles a security-only config and passes it via
--config <path> --no-eslintrc. The bundled rules are:
| Rule | Source | Severity | What it catches |
|---|---|---|---|
no-eval | Core | error | Direct eval(expr) calls. |
no-implied-eval | Core | error | setTimeout(string, ms), setInterval(string, ms), and friends. |
no-new-func | Core | error | new Function('arg', body) indirect eval. |
no-script-url | Core | error | javascript: URLs in href / src / location.href. |
no-octal-escape | Core | error | Octal escapes deprecated in ES5 strict mode. |
no-prototype-builtins | Core | error | obj.hasOwnProperty(...) (prototype-pollution shape). |
@salesforce/lwc/no-deprecated-api-usage | Plugin | error | Deprecated Salesforce API surfaces. |
@salesforce/lwc/no-document-query | Plugin | error | document.querySelector instead of this.template.querySelector (shadow-root leak / XSS surface). |
@salesforce/lwc/no-async-operation | Plugin | warn | Free-floating setTimeout / setInterval outside the LWC lifecycle. |
@salesforce/lwc/valid-api | Plugin | error | @api-decorated properties that bypass input validation. |
@salesforce/aura/no-bound-action | Plugin | error | Aura Action.setCallback(this, ...) with bound function references (callback confusion). |
Formatting and style rules (semi, indent, quotes, etc) are
deliberately excluded per Vulkro's "security findings only" manifesto.
Finding shape
Every wrapped ESLint message becomes a SecurityFinding with:
idrendered into the message asESLINT-LWC-<rule>orESLINT-AURA-<rule>based on the file path.severity: ESLinterror-> VulkroHigh, ESLintwarn-> VulkroMedium.owasp_categorychosen from the rule name:/eval|new-func|script-url/->SoftwareIntegrityFailures/query|api|bound-action/->UnsafeConsumptionOfAPIs- everything else ->
SecurityMisconfiguration
confidence:Medium. ESLint's AST patterns do not have Vulkro's cross-file taint confirmation, so the wrapper does not claim High.remediation: hand-written per-rule advice that names the LWC / Aura idiom you should switch to.
Example mapped JSON finding (truncated for the doc):
{
"id": "uuid-omitted",
"owasp_category": "SoftwareIntegrityFailures",
"severity": "High",
"file": "force-app/main/default/lwc/redirector/redirector.js",
"line": 5,
"message": "ESLINT-LWC-no-script-url: Script URL is a form of eval (5:14 to 5:41)",
"remediation": "Replace `javascript:` URLs with a proper event handler or `lightning-navigation` call. ...",
"confidence": "medium",
"confidence_reason": "wrapped ESLint rule `no-script-url` (pattern match, no Vulkro dataflow confirmation)"
}
Binary discovery
Order, first hit wins:
VULKRO_ESLINT_BINenv var, treated as the absolute path to the binary.eslinton$PATH.npx eslinton$PATH.
If none resolve, the scan exits with code 2 and a message naming the
install command. Example error:
✗ --include-eslint: ESLint is not installed and Node.js / npx is not
on $PATH. Install Node.js + ESLint: `npm install -g eslint
@salesforce/eslint-plugin-lwc @salesforce/eslint-plugin-aura`, or set
`VULKRO_ESLINT_BIN=/path/to/eslint`.
Exit codes
The wrapper inherits the standard vulkro scan contract:
| Code | Meaning |
|---|---|
0 | No findings (including no wrapper findings). |
1 | Findings reported by either Vulkro or the wrapper. |
2 | Operational error: ESLint missing, malformed JSON output, ESLint configuration failure (exit code 2 from ESLint itself). |
AppExchange Security Review
Every wrapper finding routes to the Lightning Component Security
row in vulkro sf-appexchange-report regardless of which concrete
ESLint rule fired, because all wrapped rules target a component-layer
concern (XSS surface, code injection inside a controller, deprecated
component API, input-validation gap on an @api property).
Comparison with sfdx-scanner
| Capability | sfdx-scanner | Vulkro |
|---|---|---|
| ESLint over LWC + Aura | via --engine eslint-lwc | --include-eslint |
| Curated security-only config | no (loads project .eslintrc) | yes (bundled, ships with Vulkro) |
| Output format | text / JSON / JUnit / SARIF | table / JSON / SARIF / NDJSON / JUnit / CSV / gh-pr / CycloneDX / SPDX / PDF / RoPA |
| Native scanner integration | separate run | merged into the same findings list |
| Offline operation | requires sf CLI plus Node | wrapper requires ESLint; the rest of Vulkro is fully offline |