VisCommandsvis secrets

vis secrets

Scan the workspace for hardcoded credentials with a gitleaks-compatible Rust engine

vis secrets

Scan the workspace (or a subset) for hardcoded secrets and credentials. vis secrets is a workspace-aware wrapper around @visulima/secret-scanner — a Rust port of the gitleaks detection engine — that adds git-native file selection (--staged, --since, --affected), baseline tooling, SARIF rendering, opt-in rule presets, and optional live validation against provider APIs.

Usage

vis secrets [paths...] [options]

Positional paths default to the workspace root. Pass one or more directory or file paths to scope the scan.

Examples

# Scan the workspace (grouped, colourised output)
vis secrets

# Pre-commit mode — scan only files staged for the current commit
vis secrets --staged

# Scan only files changed since a ref
vis secrets --since main

# Scan projects affected by the current branch (git diff against HEAD~1 or $VIS_BASE)
vis secrets --affected

# Seed an initial baseline from current findings
vis secrets --init

# Preview the baseline without writing files
vis secrets --init --dry-run

# Enable opt-in rule groups additively (defaults still fire)
vis secrets --enable-rule tag:preset:weak-passwords
vis secrets --enable-rule tag:preset:password-manager
vis secrets --enable-rule tag:preset:exposed-files

# Restrict output to one opt-in group only (whitelist)
vis secrets --include-rule tag:preset:password-manager

# Audit a release artefact for accidentally-shipped exposures
vis secrets dist --enable-rule tag:preset:exposed-files

# Single-rule spot check
vis secrets --include-rule stripe-access-token

# Drop a noisy rule but keep the rest of the defaults
vis secrets --exclude-rule generic-api-key

# Raise the confidence floor — CI-friendly precision filter
vis secrets --min-confidence high

# Live-verify findings against provider APIs, then fail CI on unverified matches
vis secrets --validate --only-verified

# List non-HTTP validators referenced by the ruleset + install hints
vis secrets --list-validators

# Baseline suppression + diff
vis secrets --baseline .secrets-baseline.json

# Merge current findings into the baseline and exit 0
vis secrets --update-baseline

# SARIF output for GitHub code scanning
vis secrets --format sarif > report.sarif

Modes

vis secrets picks the scan target from the first matching flag (in order):

FlagSourceBest for
--stagedgit diff --cached --name-onlyPre-commit hooks
--since <ref>git diff <ref>..HEAD --name-onlyCI on pull-request branches
--affectedgit diff $VIS_BASE..HEAD (default HEAD~1)Incremental CI / monorepos
(none — default)Positional paths, else workspace rootFull audit / seeding

--staged, --since, and --affected all require a git working tree — the command exits with code 2 if none is detected (except --affected, which falls back to a full scan with a warning).

Alongside those, three flags run a one-shot reporting pass instead of scanning:

  • --init scaffolds .secrets-baseline.json from current findings. It refuses to overwrite an existing baseline; delete it first to re-init. Pair with --dry-run to preview.
  • --list-rules prints every compiled rule (id, description, keywords, tags) and exits.
  • --list-validators prints non-HTTP validator types referenced by the current ruleset with npm add … hints for the optional peer dependencies that unlock them.

Options

Input selection

OptionTypeDefaultDescription
--stagedbooleanfalseScan only files staged for commit. Requires git.
--since <ref>stringScan only files changed since <ref> (e.g. main, origin/HEAD).
--affectedbooleanfalseScan only files changed against $VIS_BASE (default HEAD~1).
--exclude <pattern>string[]Gitignore-syntax pattern to exclude from the walk. Repeatable.
--exclude-from <path>string[]Gitignore-shaped file the walker should honor (e.g. .secretsignore). Repeatable.
--include-hiddenbooleanfalseVisit dotfiles and hidden directory entries.
--no-gitignorebooleanfalseDo not respect .gitignore / .ignore / global excludes.
--max-size <bytes>number10 MiBSkip files larger than this.

Rule selection

OptionTypeDefaultDescription
--enable-rule <spec>string[]Additive — turn on opt-in rules without restricting output. Rule id or tag:<name>. Repeatable.
--include-rule <spec>string[]Whitelist — only emit matching findings. Implies enablement. Rule id or tag:<name>. Repeatable.
--exclude-rule <spec>string[]Blacklist — drop matching findings. Rule id or tag:<name>. Repeatable.
--min-confidence <lvl>stringlowDrop rules whose author-declared confidence is below this floor: low, medium, high.
--config <path>stringPath to a gitleaks-compatible JSON config.
--no-extend-bundledbooleanfalseWith --config, replace the bundled ruleset instead of layering on top of it.

Bundled opt-in groups: tag:preset:weak-passwords (low-entropy credentials complementing generic-api-key), tag:preset:password-manager (1Password / Bitwarden / LastPass / KeePass / browser-CSV export detection), tag:preset:exposed-files (37 path-driven rules covering committed .env, .git/, .aws/credentials, private keys, DB dumps, source maps with sourcesContent, lockfiles in dist/, IDE workspace dumps, …). All three ship defaultEnabled: false. Shorthand alternative: list them under secrets.config.presets in vis.config.ts (see below) and skip the long tag:preset:* strings on the CLI.

Confidence semantics: every bundled gitleaks rule defaults to low (no explicit label). Raising the floor to medium or high drops every unlabeled rule along with explicit low-confidence rules, so a ruleset needs confidence metadata before --min-confidence high is useful.

Validation

OptionTypeDefaultDescription
--validatebooleanfalseLive-verify findings against the provider's API after detection.
--only-verifiedbooleanfalseWith --validate, drop every finding whose validation is not verified. Useful for CI.
--list-validatorsbooleanfalsePrint non-HTTP validator types referenced by the current ruleset, with peer-dep install hints.

Validation sends one HTTP request per finding (per-host concurrency capped at 4, global at 8). Supports Kingfisher-style HTTP validators with StatusMatch / WordMatch response matchers. Other validation kinds (gRPC, multi-step HTTP, checksum) mark the finding as validation=skipped — they don't block the pass.

Warning: --validate sends the candidate secret to the provider. Some providers alert their security team on failed auth attempts. Only enable on repos you own or have explicit authorisation to test.

Output

OptionTypeDefaultDescription
--formatstringtextOutput format: text, json, sarif.
--redactbooleanfalseMask the match and secret strings in every emitted finding.
--quietbooleanfalseSuppress progress output. Only findings are emitted.
--verbosebooleanfalsePrint diagnostic info to stderr (skipped rules, invalid regex, etc.).
--concurrency <n>numberautoRayon worker threads. 0 / omit = auto.

text is the default TTY format — grouped per file, colourised when stdout is a TTY. json emits an array of Finding objects with paths relative to the workspace root. sarif emits SARIF v2.1.0 with file:// URIs, a tool.driver.rules[] cross-reference, and result.level — compatible with GitHub code scanning and GitLab security dashboards.

Baseline

OptionTypeDefaultDescription
--baseline <path>string.secrets-baseline.jsonSuppress findings whose fingerprint already appears in the baseline.
--initbooleanfalseScaffold a baseline from current findings. Refuses to overwrite.
--dry-runbooleanfalseWith --init, preview without writing files.
--update-baselinebooleanfalseMerge current findings into the baseline and exit 0.
--replace-baselinebooleanfalseWith --update-baseline, replace rather than merge.

Baselines are fingerprint-keyed JSON files (<file>:<ruleID>:<startLine>) committed to the repo. A missing file is treated as empty; a malformed file emits a stderr warning but never fails the scan. When a baseline is present the default text output appends a diff summary (+N new, N unchanged, -N resolved).

Exit codes

CodeMeaning
0No findings after suppression, or --update-baseline succeeded.
1One or more findings emitted.
2Usage / configuration error (invalid flag value, no git tree).

Workspace config

Commit defaults once in vis.config.ts under secrets. The grouped shape mirrors ScanOptions:

import { defineConfig } from "@visulima/vis/config";

export default defineConfig({
    secrets: {
        baseline: ".secrets-baseline.json",
        config: {
            extendBundled: true,
            minConfidence: "medium",
            onlyVerified: false,
            // Opt-in preset shorthand — each entry expands to `tag:preset:<name>`
            // and is merged with `rules.enable`. See "Bundled opt-in groups"
            // above for the available presets.
            presets: ["weak-passwords", "exposed-files"],
            validate: false,
        },
        rules: {
            // `enable` still works for ad-hoc rule ids or tags; `presets` is the
            // ergonomic path for the bundled groups.
            exclude: ["generic-api-key"],
        },
        redact: false,
        walk: {
            excludeFromFiles: [".secretsignore"],
            excludePatterns: ["dist/**", "coverage/**"],
            gitignore: true,
            includeHidden: false,
            maxFileSize: 10 * 1024 * 1024,
        },
    },
});

CLI flags always take precedence over the config file. The full reference lives in @visulima/secret-scanner → Configuration.

Pre-commit hook

vis hook add secrets

Appends a managed block to .husky/pre-commit (or creates one) that runs vis secrets --staged --quiet. Remove the block — or delete the file — to disable.

CI recipe (SARIF upload)

# .github/workflows/secrets.yml
name: Secrets
on: [push, pull_request]
jobs:
    scan:
        runs-on: ubuntu-latest
        permissions:
            security-events: write
            contents: read
        steps:
            - uses: actions/checkout@v4
              with: { fetch-depth: 0 }
            - uses: pnpm/action-setup@v4
            - run: pnpm install --frozen-lockfile
            - run: pnpm vis secrets --format sarif > report.sarif
              continue-on-error: true
            - uses: github/codeql-action/upload-sarif@v3
              with: { sarif_file: report.sarif }

For pull-request gating without a baseline, swap the scan command for:

pnpm vis secrets --since origin/${{ github.base_ref }} --min-confidence medium

Migrating from other tools

vis migrate ports existing gitleaks / secretlint setups to vis secrets:

vis migrate gitleaks     # keeps gitleaks.toml, rewrites scripts and hooks
vis migrate secretlint   # removes @secretlint/*, rewrites scripts and hooks
vis migrate verify       # sanity-check the migration
Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues