vulkro inspect
Surface the malicious-capability shapes in a just-cloned project so a human can review them before running any of its code. This is defensive tooling: an "antivirus for source you have not run yet".
inspect projects the shipped mal_* detectors into a grouped
capability surface (credential exfiltration, install hooks, reverse
shells, obfuscation, trojan-source text, and so on) and prints each site
to review by hand.
inspect never certifies code clean
There is no clean / safe / pass / proceed state, and no zero-count reassurance. Every report carries this disclosure verbatim:
This is a static scan of code that has not run, over source an author may have crafted to evade it: it surfaces behaviors for a human to review and can never certify the code free of malicious behavior.
An empty result renders as "No known malicious-capability shapes were surfaced in 0 findings. This is not a safety guarantee." That wording is enforced by test: the renderer refuses to emit the words clean, safe, proceed, or allow in either the empty or the non-empty case.
Usage
vulkro inspect [PATH]
| Argument | Description | Default |
|---|---|---|
PATH | Path to the project root to inspect. | . |
Flags
| Flag | Description |
|---|---|
--json | Emit the machine-readable capability manifest (the CapabilityReport structure) as JSON instead of the text surface. Intended for an agent to consume before running code. The JSON always carries the non-guarantee disclosure and never a safe / clean / proceed verdict. |
How it differs from scan
Unlike vulkro scan, inspect uses the unfiltered finding
set. It deliberately ignores the vuln-scan precision floor (scan's
default --min-confidence) so that Medium-confidence shapes - for
example a committed opaque binary - are never hidden. A malware shape
that would be dropped by the confidence floor still reaches your eyes
here.
scan answers "is this code vulnerable". inspect answers "what can
this code do if I run it".
Capability groups
Each mal- evidence signal maps to one capability bucket. The surface
groups hits by bucket, sorted by count descending then label ascending.
| Capability | What it means | Signal |
|---|---|---|
| Hidden or misleading source text (trojan source) | Unicode bidi overrides, homoglyph or invisible-character tricks that make the rendered source differ from what a compiler or interpreter sees. | mal-trojan-source |
| Opens a shell or reads instance metadata (backdoor shape) | A reverse shell, an nc -e backdoor, or a cloud instance-metadata (IMDS) credential grab. | mal-reverse-shell, mal-imds |
| Reads credentials or secret files | Reads a credential store or secret file (~/.ssh, ~/.aws, keychains, token files). | mal-cred-read |
| Reads and exfiltrates credentials | Reads credentials and sends them off the machine in the same file. | mal-cred-exfil |
| Runs code from an install or build hook | Code that runs from a package or build install hook (git hook, setup.py, build.rs, Makefile fetch-pipe). | mal-install-hook |
| Obfuscated or packed source | Heavy base64 / hex blobs, dynamic decode into eval, string-array unpacking. | mal-obfuscation |
| Execution gated on environment, date, or host (logic-bomb shape) | Execution fenced behind an environment, date, hostname, or not-in-CI gate. | mal-env-gate |
| Self-propagating / worm behavior | Source that copies or re-publishes itself across packages or repos. | mal-worm |
| Reads or targets cryptocurrency wallet material | Wallet files, seed phrases, clipboard address swap. | mal-wallet |
| Fetches and runs remote code | Download-and-eval, remote module load at runtime. | mal-remote-load |
| Installs persistence on the machine | Cron, launchd, systemd, shell-rc, autostart. | mal-persist |
| Committed opaque binary the scanners cannot read | A committed native binary or executable blob the source scanners cannot read: the xz-utils blind spot. | mal-committed-binary |
| Dependency-integrity anomaly | Lockfile / manifest mismatch, integrity-hash gap. | mal-dep-integrity |
| Prompt-injection payload aimed at an AI agent | A payload aimed at an AI agent reading the repo. | mal-prompt-injection |
| Other malicious-capability shape | Any other mal- signal that does not map to a named bucket. Newly added detectors land here rather than dropping out of the surface. | any other mal-* |
Individual sites carry a MAL-* rule id parsed from the finding message
(for example MAL-EXFIL-001, MAL-HOOK-003, MAL-TROJAN-002), or the
raw mal- signal when the message has no id prefix.
Text output
The default view lists each capability group with its count, then up to
three example sites, then a ... and N more site(s) line when the group
has more. The disclosure closes the report.
Capability surface: 4 malicious-capability finding(s) across 2 capability group(s).
Each item below is a behavior to review by hand, not a verdict.
- Reads and exfiltrates credentials (3 finding(s))
MAL-EXFIL-001 at scripts/postinstall.js:12
MAL-EXFIL-001 at scripts/postinstall.js:31
MAL-EXFIL-001 at src/telemetry.js:8
- Runs code from an install or build hook (1 finding(s))
MAL-HOOK-002 at package.json:14
JSON output
--json emits the CapabilityReport structure:
| Field | Description |
|---|---|
capabilities[] | One entry per capability bucket: capability, label, count, and hits[]. |
capabilities[].hits[] | Each site: file, line (1-based), rule_id, and the verbatim finding message. |
total_findings | Total malicious-capability findings projected (the sum of all counts). |
disclosure | The non-guarantee sentence, carried on the report so every consumer renders it. |
There is no verdict field. Nothing in the JSON says safe, clean, or proceed.
Exit codes
0ran and surfaced no known malicious-capability shapes. This is not a pass and not a safety guarantee: static analysis over unrun, potentially adversarial source cannot see everything.1malicious-capability shapes were surfaced: human review is required before trusting or running this code.2error (bad path, IO failure, internal crash).
Privacy
inspect renders locally. No finding data leaves the machine.
Examples
# Review a repo you just cloned, before running its install script.
git clone https://example.com/some/repo && cd repo
vulkro inspect .
# Machine-readable manifest for an agent to read before running code.
vulkro inspect . --json > capabilities.json
From an AI agent
The same surface is exposed over MCP as the inspect_repo tool, so an
agent can check a repository before running any of its code. See
vulkro mcp.
Not to be confused with
vulkro-live inspect is a different command in the
free Vulkro Labs CLI: it answers "is this MCP server safe to add" by
resolving a server spec to its backing registry package. vulkro inspect
reviews source you already have on disk.
Related
vulkro scan- the full security pipeline, with the confidence floor applied.vulkro guard- the in-loop gate.vulkro mcp- theinspect_repoMCP tool.- Confidence model - the precision floor
that
inspectdeliberately bypasses.
Command reference
Generated from vulkro help inspect on vulkro 0.26.0. This block is the
authoritative flag, usage, and exit-code reference for this command; the
prose above is the friendly explanation. Do not edit this block by hand;
run npm run docs:cli after a release.
Look for malicious-code patterns in source you have not run yet.
Vulkro Inspect: surface the malicious-capability shapes in a just-cloned project for human review (an "antivirus for source you have not run yet"). This is DEFENSIVE tooling.
It projects the shipped `mal_*` malware detectors into a grouped capability surface (credential exfiltration, install hooks, reverse shells, obfuscation, trojan-source text, and so on) and prints each site to review by hand. Unlike `scan`, Inspect uses the UNFILTERED findings: it deliberately ignores the vuln-scan precision floor so that Medium-confidence shapes (for example a committed opaque binary) are never hidden.
Inspect NEVER certifies code safe. There is no clean / safe / pass / proceed state and no zero-count reassurance: it is a static scan of code that has not run, over source an author may have crafted to evade it, so it can only surface behaviors for a person to judge.
Exit codes: `0` ran and surfaced no known malicious-capability shapes. This is NOT a pass and NOT a safety guarantee: static analysis over unrun, potentially adversarial source cannot see everything. `1` malicious-capability shapes were surfaced: human review is required before trusting or running this code. `2` error (bad path, IO failure, internal crash).
Usage: vulkro inspect [OPTIONS] [PATH]
Arguments:
[PATH]
Path to the project root to inspect (default: current directory)
[default: .]
Options:
--json
Emit the machine-readable capability manifest (the `CapabilityReport` structure) as JSON instead of the text surface. Intended for an agent to consume before running code. The JSON always carries the non-guarantee disclosure and never a safe / clean / proceed verdict
--offline
Hard-disable every outbound network call for this run (sets VULKRO_OFFLINE=1). Blocks the CVE feed, the license heartbeat, the update check, webhooks, and any cloud AI endpoint; a loopback model (http://127.0.0.1, http://localhost) is still allowed. Equivalent to exporting VULKRO_OFFLINE=1, and the flag wins when both are set
--ai
[Advisory] Attach a local-model plain-language explanation to each surfaced capability: WHY the flagged shape is suspicious and what to check. ADDITIVE and OPT-IN: the deterministic detection is unchanged and remains the source of truth; the AI text is a labelled advisory overlay (advisory / non-deterministic / excluded-from-benchmark) and never changes what was surfaced or the exit code. Uses the AI layer resolved from flags / env / `vulkro ai use` (defaults to a local loopback model, which is allowed even under `VULKRO_OFFLINE`; a cloud endpoint is refused offline). If the model is unreachable the overlay is skipped with a stderr note and the deterministic report is unaffected
-h, --help
Print help (see a summary with '-h')