Skip to main content

Secrets detection

Vulkro detects hardcoded API keys, tokens, passwords, connection strings, and private keys across:

  • .env* files (always scanned, even with --scope src)
  • Source code (Python, JS/TS, Go)
  • Config files (*.yaml, *.yml, *.toml, *.json)
  • IaC (Terraform, Helm)
  • Kubernetes manifests
  • Git history (last 500 commits, up to 2 years)

Provider-format escalation

Generic patterns (api_key = "...") start at Medium confidence. When the detected value matches a known provider format, confidence is bumped to High automatically:

FormatProvider
sk_live_*Stripe live key
AKIA*AWS access key
ghp_*, gho_*, ghu_*, ghs_*GitHub token
xoxb-*, xoxa-*, xoxp-*Slack token
SG.*SendGrid
hf_*Hugging Face
glpat-*GitLab personal access token

The full list ships with Vulkro and is growing.

Live validation (opt-in)

vulkro scan . --validate-secrets

Each detected secret is probed against the matching provider's "whoami" / "verify" endpoint. Results tag the finding:

  • [live] - credential is currently valid.
  • [dormant] - credential format matches but the API call returned 401/403, suggesting the key was rotated.
  • [unknown] - provider doesn't expose a no-op verification endpoint, or network call failed.

[live] findings are bumped to Critical. The probe is rate-limited and sequential to avoid tripping abuse detection.

Git-history audit

Even after you remove a secret from the working tree, it lives in git log. Vulkro walks the last 500 commits (or 2 years, whichever is shorter):

SECRETS 19 in git history
| a1b2c3d feat: integrate Stripe sk_live_... (3 occurrences)
| 4e5f6g7 setup CI AKIA...

The audit honours .gitignore for the current tree (so you don't get spammed by old vendored dirs) but not for historical commits - secrets committed and later .gitignored are still surfaced.

Suppression

# vulkro-disable-next-line HardcodedSecret
TEST_API_KEY = "sk_test_FAKE"

Inline pragmas work the same way as for OWASP findings. See vulkro scan.