An open-source secret scanning CLI for Go that scans Git history, CI logs, environment files, and Docker layers, then reports prioritized alerts.
go install github.com/nobuo-miura/SecretLens/cmd/secretlens@latestgit clone https://github.com/nobuo-miura/SecretLens.git
cd SecretLens
make build # creates bin/secretlens
make install # installs to $GOPATH/bin/secretlens# Scan Git history and environment files (default)
secretlens scan .
# Explicitly scan Git history and environment files
secretlens scan --all .
# Scan CI logs from GitHub Actions
secretlens scan --source=cilog --repo=owner/repo
# Scan Docker image layers
secretlens scan --source=docker --image=myapp:latest
# Write SARIF output
secretlens scan --format=sarif --out=results.sarif .
# Generate an HTML report
secretlens scan --format=html --out=report.html .
# Return exit code 1 when findings meet the severity threshold
secretlens scan --fail-on=HIGH .
# Scan staged changes only (pre-commit)
secretlens scan --staged .
# Scan uncommitted changes to tracked files in the working tree
secretlens scan --source=worktree .
# Scan only the commits new to this branch (fast PR scans in CI)
secretlens scan --commit-range=origin/main..HEAD .| Flag | Description | Default |
|---|---|---|
--all |
Scan Git history and environment files | false |
--source |
Scan source: git envfile all worktree staged cilog docker |
git+envfile |
--staged |
Scan staged changes only (alias for --source=staged, for pre-commit) |
false |
--since |
Scan history from the given commit only (<commit>..HEAD) |
- |
--commit-range |
Scan the given commit range only (base..head) |
- |
--config |
Config file path (auto-detects .secretlens.yml in the scan target) |
- |
--format |
Output format: text json sarif html github-pr |
text |
--out |
Output file path. Writes to stdout when omitted | - |
--fail-on |
Exit with code 1 at or above severity: CRITICAL HIGH MEDIUM LOW |
- |
--rules-dir |
Directory of additional / overriding YAML rules | none (embedded rules only) |
--baseline |
Baseline file path | .secretlens.baseline.json |
--repo |
GitHub repository in owner/repo format, used by cilog |
- |
--gitlab-url |
GitLab instance URL, used by cilog |
- |
--project-id |
GitLab project ID, used by cilog |
- |
--image |
Docker image name, used by docker |
- |
--pr |
Pull request number for posting a PR comment | - |
--sha |
Commit SHA for creating a Check Run | - |
--github-token |
GitHub API token. GITHUB_TOKEN is also supported |
- |
--slack-webhook |
Slack webhook URL. SLACK_WEBHOOK_URL is also supported |
- |
--verify |
Run live API verification for supported rules (opt-in; currently GitHub tokens only) | false |
Scan all repositories in a GitHub Organization concurrently.
secretlens org --org=my-company --format=html --out=audit.html| Flag | Description | Default |
|---|---|---|
--org |
GitHub Organization name (required) | - |
--token |
GitHub API token. GITHUB_TOKEN is also supported |
- |
--concurrency |
Number of concurrent scans | 4 |
--format |
Output format: text json html |
text |
--out |
Output file path | - |
--rules-dir |
Directory of additional / overriding YAML rules | none (embedded rules only) |
secretlens baseline update . # scan and add all current findings to the baseline
secretlens baseline list # list registered fingerprintssecretlens rules list # list enabled rules with ID, severity, and nameEach finding receives a score, which is then mapped to a severity level.
| Condition | Score |
|---|---|
| Base rule: CRITICAL | +60 |
| Base rule: HIGH | +40 |
| Base rule: MEDIUM | +20 |
| Live verification passed | +50 |
Entropy at or above the rule's entropy_min (or > 4.5 when unset) |
+20 |
Sensitive file name such as .env or credentials |
+15 |
| Test code | -30 |
Comment lines are skipped entirely and never produce findings.
| Score | Severity |
|---|---|
| 60 or higher | CRITICAL |
| 40-59 | HIGH |
| 20-39 | MEDIUM |
| Below 20 | LOW |
Standard rules are embedded in the binary. Put YAML files in any directory and pass it via --rules-dir to add rules (same IDs override embedded ones).
# rules/my-company.yaml
rules:
- id: myco-internal-token
name: MyCompany Internal Token
severity: CRITICAL
pattern: 'MYCO_[A-Za-z0-9]{32}'
entropy_min: 4.0
context_exclude:
- "**/*_test.go"
- "**/testdata/**"
tags:
- myco
- internal| Field | Type | Description |
|---|---|---|
id |
string | Unique rule ID (required) |
name |
string | Display name (required) |
severity |
string | CRITICAL HIGH MEDIUM LOW (required) |
pattern |
string | Regular expression using Go regexp syntax (required) |
entropy_min |
float | Minimum entropy threshold (optional) |
context_exclude |
[]string | Exclusion glob patterns (optional) |
tags |
[]string | Tags (optional) |
Place .secretlens.yml (or .secretlens.yaml) in the scan target directory, or pass --config, to share the same settings between CI and local runs. Explicitly passed CLI flags always take precedence over the config file.
# .secretlens.yml
source: all
format: sarif
out: results.sarif
fail_on: HIGH
rules_dir: ./custom-rules
baseline: .secretlens.baseline.json
exclude: # global exclude globs, applied to git / worktree / staged / envfile / docker scans
- "**/vendor/**"
- "**/testdata/**"Notes:
- Relative paths (
rules_dir,baseline,out) are resolved relative to the config file's directory. outis only applied when the config file is passed explicitly via--config. Auto-detected configs come from the scanned repository, which must not be able to choose where results are written.- The Slack webhook URL is itself a secret and is intentionally not supported in the config file — use the
--slack-webhookflag or theSLACK_WEBHOOK_URLenvironment variable.
#!/bin/sh
# .git/hooks/pre-commit
exec secretlens scan --staged --fail-on=HIGH .Add known false positives to a baseline file so future scans can ignore them.
# Scan and add all current findings to the baseline
secretlens baseline update .
# List registered fingerprints
secretlens baseline list
# Inspect fingerprints of the current scan
secretlens scan --format=json . | jq -r '.[].fingerprint'
# Add fingerprints manually to .secretlens.baseline.json
{
"fingerprints": {
"abc123...": true
}
}# .github/workflows/secretlens.yml
name: Secret Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # fetch full Git history
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- name: Install SecretLens
run: go install github.com/nobuo-miura/SecretLens/cmd/secretlens@latest
- name: Scan
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
secretlens scan \
--all \
--format=sarif \
--out=results.sarif \
--fail-on=HIGH \
.
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: results.sarif
- name: PR Comment
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
secretlens scan \
--all \
--format=github-pr \
--repo=${{ github.repository }} \
--pr=${{ github.event.pull_request.number }} \
--sha=${{ github.sha }} \
.| File | Coverage |
|---|---|
rules/aws.yaml |
AWS Access Key ID / Secret Access Key |
rules/gcp.yaml |
GCP Service Account Key / API Key |
rules/azure.yaml |
Azure Storage Account Key / Connection String |
rules/github.yaml |
GitHub Token |
rules/jwt.yaml |
JWT Token |
rules/generic.yaml |
API Key / Password / Token / Private Key / Connection String |
make test # run tests
make check # run vet, tests, and lint
make run-scan # run a sample scan
make report-html # generate and open an HTML report
make release # cross-compile for major platforms
make help # show available commandssecretlens/
|-- cmd/secretlens/ # CLI entrypoint (cobra)
|-- internal/
| |-- scanner/
| | |-- git/ # streaming parser for git log --all -p
| | |-- cilog/ # GitHub Actions / GitLab CI log APIs
| | |-- envfile/ # scan .env / .tfvars / *.yaml files
| | `-- docker/ # scan Docker image layers
| |-- detector/
| | |-- regex/ # YAML rule loading and regex matching
| | |-- entropy/ # Shannon entropy calculation
| | |-- context/ # exclude test code and comments
| | `-- verifier/ # live API verification (currently GitHub tokens)
| |-- finding/ # Finding type and scoring
| |-- reporter/
| | |-- sarif/ # SARIF v2.1.0 output
| | |-- github/ # PR comments and Check Run API
| | |-- slack/ # Slack webhook notifications (Block Kit)
| | `-- html/ # interactive HTML reports
| |-- baseline/ # .secretlens.baseline.json management
| `-- org/ # GitHub Organization audit mode
|-- rules/ # built-in YAML rules
`-- testdata/ # sample files for tests
MIT License