leakscan 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- leakscan-0.2.0/PKG-INFO +205 -0
- leakscan-0.2.0/README.md +191 -0
- leakscan-0.2.0/leakscan.egg-info/PKG-INFO +205 -0
- leakscan-0.2.0/leakscan.egg-info/SOURCES.txt +20 -0
- leakscan-0.2.0/leakscan.egg-info/dependency_links.txt +1 -0
- leakscan-0.2.0/leakscan.egg-info/entry_points.txt +2 -0
- leakscan-0.2.0/leakscan.egg-info/requires.txt +7 -0
- leakscan-0.2.0/leakscan.egg-info/top_level.txt +1 -0
- leakscan-0.2.0/pyproject.toml +26 -0
- leakscan-0.2.0/scanner/__init__.py +0 -0
- leakscan-0.2.0/scanner/baseline.py +23 -0
- leakscan-0.2.0/scanner/cli.py +346 -0
- leakscan-0.2.0/scanner/engine.py +239 -0
- leakscan-0.2.0/scanner/entropy.py +58 -0
- leakscan-0.2.0/scanner/github/__init__.py +0 -0
- leakscan-0.2.0/scanner/github/fetcher.py +162 -0
- leakscan-0.2.0/scanner/ignorefile.py +68 -0
- leakscan-0.2.0/scanner/patterns.py +121 -0
- leakscan-0.2.0/scanner/reporter.py +287 -0
- leakscan-0.2.0/scanner/verifier.py +140 -0
- leakscan-0.2.0/setup.cfg +4 -0
- leakscan-0.2.0/tests/test_scanner.py +286 -0
leakscan-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: leakscan
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI tool to detect leaked secrets and API keys in codebases and public GitHub repos — including git history
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: click>=8.1
|
|
9
|
+
Requires-Dist: rich>=13.0
|
|
10
|
+
Requires-Dist: requests>=2.31
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# secret-scanner
|
|
16
|
+
|
|
17
|
+
A CLI tool that scans local codebases and public GitHub repos for leaked API keys and secrets — including secrets deleted from code but still alive in git history.
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
**Detection**
|
|
24
|
+
- 55+ regex patterns: AWS, GitHub, GitLab, Stripe, OpenAI, Anthropic, Slack, Twilio, Discord, Telegram, npm, PyPI, Shopify, DigitalOcean, Dropbox, Notion, Linear, Terraform, Vault, New Relic, Mapbox, Square, Mailchimp, and more
|
|
25
|
+
- Shannon entropy detection for unquoted values (`.env`, YAML, INI files)
|
|
26
|
+
- Inline suppression: `# nosec`, `# gitleaks:allow`, `# secretscanner:allow`
|
|
27
|
+
- AWS Access Key ID pattern anchored to real prefixes (`AKIA`, `AGPA`, `AROA`, etc.) — no false positives on random uppercase strings
|
|
28
|
+
|
|
29
|
+
**Verification**
|
|
30
|
+
- `--verify` makes live API calls to check if found secrets are still active
|
|
31
|
+
- Supports: GitHub, GitLab, Stripe, OpenAI, Anthropic, HuggingFace, SendGrid, Slack, npm, Replicate
|
|
32
|
+
|
|
33
|
+
**Scanning scope**
|
|
34
|
+
- Local file trees (parallel, 8 threads)
|
|
35
|
+
- Git history: commits, any branch, with `--since DATE` for date-bounded scans
|
|
36
|
+
- GitHub profile: all public repos for a user or org
|
|
37
|
+
- GitHub repo by URL: `secrets scan https://github.com/owner/repo`
|
|
38
|
+
- GitHub Gists: `--include-gists`
|
|
39
|
+
|
|
40
|
+
**CI/CD integration**
|
|
41
|
+
- Exit code `1` on any CRITICAL or HIGH finding
|
|
42
|
+
- SARIF output for GitHub Security tab / GitLab SAST
|
|
43
|
+
- Baseline mode: save known findings, only alert on new secrets
|
|
44
|
+
- Pre-commit hook with automatic baseline support
|
|
45
|
+
- `.secretignore` with full `**` glob support
|
|
46
|
+
|
|
47
|
+
**Output formats**
|
|
48
|
+
- Terminal (rich table with severity colors)
|
|
49
|
+
- JSON (with fingerprints and verification status)
|
|
50
|
+
- CSV
|
|
51
|
+
- SARIF 2.1.0
|
|
52
|
+
- Markdown disclosure report
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install leakscan
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or from source:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
64
|
+
cd secret-scanner
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
**Basic local scan**
|
|
71
|
+
```bash
|
|
72
|
+
secrets scan ./myproject
|
|
73
|
+
secrets scan . --severity HIGH --no-entropy
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Scan git history** (catches deleted secrets)
|
|
77
|
+
```bash
|
|
78
|
+
secrets scan . --history
|
|
79
|
+
secrets scan . --history --depth 500 --since 2023-01-01
|
|
80
|
+
secrets scan . --history --branch main
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Verify secrets are live**
|
|
84
|
+
```bash
|
|
85
|
+
secrets scan . --verify
|
|
86
|
+
secrets scan . --verify --severity HIGH
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Scan a public GitHub repo by URL**
|
|
90
|
+
```bash
|
|
91
|
+
secrets scan https://github.com/owner/repo
|
|
92
|
+
secrets scan https://github.com/owner/repo --history --verify
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Scan a GitHub user's repos and gists**
|
|
96
|
+
```bash
|
|
97
|
+
secrets scan --github username
|
|
98
|
+
secrets scan --github username --include-gists
|
|
99
|
+
secrets scan --github username --history --token $GITHUB_TOKEN
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Baseline mode** (CI-friendly: only alert on new findings)
|
|
103
|
+
```bash
|
|
104
|
+
secrets scan . --save-baseline .secrets.baseline
|
|
105
|
+
secrets scan . --baseline .secrets.baseline
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Output formats**
|
|
109
|
+
```bash
|
|
110
|
+
secrets scan . --format json --output results.json
|
|
111
|
+
secrets scan . --format csv --output findings.csv
|
|
112
|
+
secrets scan . --format sarif --output results.sarif
|
|
113
|
+
secrets scan --github username --format disclosure --output report.md
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Redact secrets in output** (safe for shared logs)
|
|
117
|
+
```bash
|
|
118
|
+
secrets scan . --redact
|
|
119
|
+
secrets scan . --format json --redact --output safe-results.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Install as pre-commit hook
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cd your-git-repo
|
|
126
|
+
secrets install-hook
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The hook uses `.secrets.baseline` automatically if present, suppressing already-known findings.
|
|
130
|
+
|
|
131
|
+
To suppress a specific line: add `# nosec` or `# gitleaks:allow` to the line.
|
|
132
|
+
|
|
133
|
+
## .secretignore
|
|
134
|
+
|
|
135
|
+
Create `.secretignore` in your project root to exclude paths:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
tests/fixtures/**
|
|
139
|
+
vendor/**
|
|
140
|
+
*.example
|
|
141
|
+
docs/
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Supports full `**` glob syntax (like `.gitignore`).
|
|
145
|
+
|
|
146
|
+
## GitHub Actions
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
- name: Scan for secrets
|
|
150
|
+
run: secrets scan . --severity HIGH --no-entropy --format sarif --output results.sarif
|
|
151
|
+
|
|
152
|
+
- name: Upload SARIF
|
|
153
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
154
|
+
with:
|
|
155
|
+
sarif_file: results.sarif
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Severity levels
|
|
159
|
+
|
|
160
|
+
| Level | Examples |
|
|
161
|
+
|----------|----------|
|
|
162
|
+
| CRITICAL | Private keys (RSA/EC/PGP/OpenSSH/PKCS#8), AWS credentials, Azure storage keys |
|
|
163
|
+
| HIGH | GitHub/GitLab tokens, Stripe live keys, OpenAI/Anthropic keys, Slack tokens, npm/PyPI tokens, Telegram/Discord bots |
|
|
164
|
+
| MEDIUM | Generic API keys, hardcoded passwords, JWT tokens, database URLs, Stripe test keys |
|
|
165
|
+
| LOW | High-entropy strings (possible unknown secrets) |
|
|
166
|
+
|
|
167
|
+
## Why history scanning matters
|
|
168
|
+
|
|
169
|
+
Deleting a secret from your latest commit does **not** remove it from git history. Anyone who clones your repo can run `git log -p` and recover it. Most scanners miss this completely.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Find secrets that were committed at any point in the last year
|
|
173
|
+
secrets scan . --history --depth 1000 --since 2024-01-01
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Architecture
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
scanner/
|
|
180
|
+
cli.py entry point (click)
|
|
181
|
+
engine.py file walker, parallel scanner, git history, shared kernel
|
|
182
|
+
patterns.py 55+ regex patterns
|
|
183
|
+
entropy.py Shannon entropy scorer (quoted + unquoted values)
|
|
184
|
+
verifier.py live API verification (10 services)
|
|
185
|
+
baseline.py save/load/compare baseline fingerprints
|
|
186
|
+
reporter.py terminal/JSON/CSV/SARIF/disclosure output
|
|
187
|
+
ignorefile.py .secretignore parser with ** glob support
|
|
188
|
+
github/
|
|
189
|
+
fetcher.py GitHub API client: repos, gists, commit history
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Contributing
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
196
|
+
cd secret-scanner
|
|
197
|
+
pip install -e ".[dev]"
|
|
198
|
+
pytest tests/
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
To add a pattern: edit `scanner/patterns.py` and add a test in `tests/test_scanner.py`.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
MIT
|
leakscan-0.2.0/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# secret-scanner
|
|
2
|
+
|
|
3
|
+
A CLI tool that scans local codebases and public GitHub repos for leaked API keys and secrets — including secrets deleted from code but still alive in git history.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
**Detection**
|
|
10
|
+
- 55+ regex patterns: AWS, GitHub, GitLab, Stripe, OpenAI, Anthropic, Slack, Twilio, Discord, Telegram, npm, PyPI, Shopify, DigitalOcean, Dropbox, Notion, Linear, Terraform, Vault, New Relic, Mapbox, Square, Mailchimp, and more
|
|
11
|
+
- Shannon entropy detection for unquoted values (`.env`, YAML, INI files)
|
|
12
|
+
- Inline suppression: `# nosec`, `# gitleaks:allow`, `# secretscanner:allow`
|
|
13
|
+
- AWS Access Key ID pattern anchored to real prefixes (`AKIA`, `AGPA`, `AROA`, etc.) — no false positives on random uppercase strings
|
|
14
|
+
|
|
15
|
+
**Verification**
|
|
16
|
+
- `--verify` makes live API calls to check if found secrets are still active
|
|
17
|
+
- Supports: GitHub, GitLab, Stripe, OpenAI, Anthropic, HuggingFace, SendGrid, Slack, npm, Replicate
|
|
18
|
+
|
|
19
|
+
**Scanning scope**
|
|
20
|
+
- Local file trees (parallel, 8 threads)
|
|
21
|
+
- Git history: commits, any branch, with `--since DATE` for date-bounded scans
|
|
22
|
+
- GitHub profile: all public repos for a user or org
|
|
23
|
+
- GitHub repo by URL: `secrets scan https://github.com/owner/repo`
|
|
24
|
+
- GitHub Gists: `--include-gists`
|
|
25
|
+
|
|
26
|
+
**CI/CD integration**
|
|
27
|
+
- Exit code `1` on any CRITICAL or HIGH finding
|
|
28
|
+
- SARIF output for GitHub Security tab / GitLab SAST
|
|
29
|
+
- Baseline mode: save known findings, only alert on new secrets
|
|
30
|
+
- Pre-commit hook with automatic baseline support
|
|
31
|
+
- `.secretignore` with full `**` glob support
|
|
32
|
+
|
|
33
|
+
**Output formats**
|
|
34
|
+
- Terminal (rich table with severity colors)
|
|
35
|
+
- JSON (with fingerprints and verification status)
|
|
36
|
+
- CSV
|
|
37
|
+
- SARIF 2.1.0
|
|
38
|
+
- Markdown disclosure report
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install leakscan
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or from source:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
50
|
+
cd secret-scanner
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
**Basic local scan**
|
|
57
|
+
```bash
|
|
58
|
+
secrets scan ./myproject
|
|
59
|
+
secrets scan . --severity HIGH --no-entropy
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Scan git history** (catches deleted secrets)
|
|
63
|
+
```bash
|
|
64
|
+
secrets scan . --history
|
|
65
|
+
secrets scan . --history --depth 500 --since 2023-01-01
|
|
66
|
+
secrets scan . --history --branch main
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Verify secrets are live**
|
|
70
|
+
```bash
|
|
71
|
+
secrets scan . --verify
|
|
72
|
+
secrets scan . --verify --severity HIGH
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Scan a public GitHub repo by URL**
|
|
76
|
+
```bash
|
|
77
|
+
secrets scan https://github.com/owner/repo
|
|
78
|
+
secrets scan https://github.com/owner/repo --history --verify
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Scan a GitHub user's repos and gists**
|
|
82
|
+
```bash
|
|
83
|
+
secrets scan --github username
|
|
84
|
+
secrets scan --github username --include-gists
|
|
85
|
+
secrets scan --github username --history --token $GITHUB_TOKEN
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Baseline mode** (CI-friendly: only alert on new findings)
|
|
89
|
+
```bash
|
|
90
|
+
secrets scan . --save-baseline .secrets.baseline
|
|
91
|
+
secrets scan . --baseline .secrets.baseline
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Output formats**
|
|
95
|
+
```bash
|
|
96
|
+
secrets scan . --format json --output results.json
|
|
97
|
+
secrets scan . --format csv --output findings.csv
|
|
98
|
+
secrets scan . --format sarif --output results.sarif
|
|
99
|
+
secrets scan --github username --format disclosure --output report.md
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Redact secrets in output** (safe for shared logs)
|
|
103
|
+
```bash
|
|
104
|
+
secrets scan . --redact
|
|
105
|
+
secrets scan . --format json --redact --output safe-results.json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Install as pre-commit hook
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
cd your-git-repo
|
|
112
|
+
secrets install-hook
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The hook uses `.secrets.baseline` automatically if present, suppressing already-known findings.
|
|
116
|
+
|
|
117
|
+
To suppress a specific line: add `# nosec` or `# gitleaks:allow` to the line.
|
|
118
|
+
|
|
119
|
+
## .secretignore
|
|
120
|
+
|
|
121
|
+
Create `.secretignore` in your project root to exclude paths:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
tests/fixtures/**
|
|
125
|
+
vendor/**
|
|
126
|
+
*.example
|
|
127
|
+
docs/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Supports full `**` glob syntax (like `.gitignore`).
|
|
131
|
+
|
|
132
|
+
## GitHub Actions
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
- name: Scan for secrets
|
|
136
|
+
run: secrets scan . --severity HIGH --no-entropy --format sarif --output results.sarif
|
|
137
|
+
|
|
138
|
+
- name: Upload SARIF
|
|
139
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
140
|
+
with:
|
|
141
|
+
sarif_file: results.sarif
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Severity levels
|
|
145
|
+
|
|
146
|
+
| Level | Examples |
|
|
147
|
+
|----------|----------|
|
|
148
|
+
| CRITICAL | Private keys (RSA/EC/PGP/OpenSSH/PKCS#8), AWS credentials, Azure storage keys |
|
|
149
|
+
| HIGH | GitHub/GitLab tokens, Stripe live keys, OpenAI/Anthropic keys, Slack tokens, npm/PyPI tokens, Telegram/Discord bots |
|
|
150
|
+
| MEDIUM | Generic API keys, hardcoded passwords, JWT tokens, database URLs, Stripe test keys |
|
|
151
|
+
| LOW | High-entropy strings (possible unknown secrets) |
|
|
152
|
+
|
|
153
|
+
## Why history scanning matters
|
|
154
|
+
|
|
155
|
+
Deleting a secret from your latest commit does **not** remove it from git history. Anyone who clones your repo can run `git log -p` and recover it. Most scanners miss this completely.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Find secrets that were committed at any point in the last year
|
|
159
|
+
secrets scan . --history --depth 1000 --since 2024-01-01
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
scanner/
|
|
166
|
+
cli.py entry point (click)
|
|
167
|
+
engine.py file walker, parallel scanner, git history, shared kernel
|
|
168
|
+
patterns.py 55+ regex patterns
|
|
169
|
+
entropy.py Shannon entropy scorer (quoted + unquoted values)
|
|
170
|
+
verifier.py live API verification (10 services)
|
|
171
|
+
baseline.py save/load/compare baseline fingerprints
|
|
172
|
+
reporter.py terminal/JSON/CSV/SARIF/disclosure output
|
|
173
|
+
ignorefile.py .secretignore parser with ** glob support
|
|
174
|
+
github/
|
|
175
|
+
fetcher.py GitHub API client: repos, gists, commit history
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Contributing
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
182
|
+
cd secret-scanner
|
|
183
|
+
pip install -e ".[dev]"
|
|
184
|
+
pytest tests/
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
To add a pattern: edit `scanner/patterns.py` and add a test in `tests/test_scanner.py`.
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: leakscan
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI tool to detect leaked secrets and API keys in codebases and public GitHub repos — including git history
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: click>=8.1
|
|
9
|
+
Requires-Dist: rich>=13.0
|
|
10
|
+
Requires-Dist: requests>=2.31
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# secret-scanner
|
|
16
|
+
|
|
17
|
+
A CLI tool that scans local codebases and public GitHub repos for leaked API keys and secrets — including secrets deleted from code but still alive in git history.
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
**Detection**
|
|
24
|
+
- 55+ regex patterns: AWS, GitHub, GitLab, Stripe, OpenAI, Anthropic, Slack, Twilio, Discord, Telegram, npm, PyPI, Shopify, DigitalOcean, Dropbox, Notion, Linear, Terraform, Vault, New Relic, Mapbox, Square, Mailchimp, and more
|
|
25
|
+
- Shannon entropy detection for unquoted values (`.env`, YAML, INI files)
|
|
26
|
+
- Inline suppression: `# nosec`, `# gitleaks:allow`, `# secretscanner:allow`
|
|
27
|
+
- AWS Access Key ID pattern anchored to real prefixes (`AKIA`, `AGPA`, `AROA`, etc.) — no false positives on random uppercase strings
|
|
28
|
+
|
|
29
|
+
**Verification**
|
|
30
|
+
- `--verify` makes live API calls to check if found secrets are still active
|
|
31
|
+
- Supports: GitHub, GitLab, Stripe, OpenAI, Anthropic, HuggingFace, SendGrid, Slack, npm, Replicate
|
|
32
|
+
|
|
33
|
+
**Scanning scope**
|
|
34
|
+
- Local file trees (parallel, 8 threads)
|
|
35
|
+
- Git history: commits, any branch, with `--since DATE` for date-bounded scans
|
|
36
|
+
- GitHub profile: all public repos for a user or org
|
|
37
|
+
- GitHub repo by URL: `secrets scan https://github.com/owner/repo`
|
|
38
|
+
- GitHub Gists: `--include-gists`
|
|
39
|
+
|
|
40
|
+
**CI/CD integration**
|
|
41
|
+
- Exit code `1` on any CRITICAL or HIGH finding
|
|
42
|
+
- SARIF output for GitHub Security tab / GitLab SAST
|
|
43
|
+
- Baseline mode: save known findings, only alert on new secrets
|
|
44
|
+
- Pre-commit hook with automatic baseline support
|
|
45
|
+
- `.secretignore` with full `**` glob support
|
|
46
|
+
|
|
47
|
+
**Output formats**
|
|
48
|
+
- Terminal (rich table with severity colors)
|
|
49
|
+
- JSON (with fingerprints and verification status)
|
|
50
|
+
- CSV
|
|
51
|
+
- SARIF 2.1.0
|
|
52
|
+
- Markdown disclosure report
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install leakscan
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or from source:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
64
|
+
cd secret-scanner
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
**Basic local scan**
|
|
71
|
+
```bash
|
|
72
|
+
secrets scan ./myproject
|
|
73
|
+
secrets scan . --severity HIGH --no-entropy
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Scan git history** (catches deleted secrets)
|
|
77
|
+
```bash
|
|
78
|
+
secrets scan . --history
|
|
79
|
+
secrets scan . --history --depth 500 --since 2023-01-01
|
|
80
|
+
secrets scan . --history --branch main
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Verify secrets are live**
|
|
84
|
+
```bash
|
|
85
|
+
secrets scan . --verify
|
|
86
|
+
secrets scan . --verify --severity HIGH
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Scan a public GitHub repo by URL**
|
|
90
|
+
```bash
|
|
91
|
+
secrets scan https://github.com/owner/repo
|
|
92
|
+
secrets scan https://github.com/owner/repo --history --verify
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Scan a GitHub user's repos and gists**
|
|
96
|
+
```bash
|
|
97
|
+
secrets scan --github username
|
|
98
|
+
secrets scan --github username --include-gists
|
|
99
|
+
secrets scan --github username --history --token $GITHUB_TOKEN
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Baseline mode** (CI-friendly: only alert on new findings)
|
|
103
|
+
```bash
|
|
104
|
+
secrets scan . --save-baseline .secrets.baseline
|
|
105
|
+
secrets scan . --baseline .secrets.baseline
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Output formats**
|
|
109
|
+
```bash
|
|
110
|
+
secrets scan . --format json --output results.json
|
|
111
|
+
secrets scan . --format csv --output findings.csv
|
|
112
|
+
secrets scan . --format sarif --output results.sarif
|
|
113
|
+
secrets scan --github username --format disclosure --output report.md
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Redact secrets in output** (safe for shared logs)
|
|
117
|
+
```bash
|
|
118
|
+
secrets scan . --redact
|
|
119
|
+
secrets scan . --format json --redact --output safe-results.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Install as pre-commit hook
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cd your-git-repo
|
|
126
|
+
secrets install-hook
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The hook uses `.secrets.baseline` automatically if present, suppressing already-known findings.
|
|
130
|
+
|
|
131
|
+
To suppress a specific line: add `# nosec` or `# gitleaks:allow` to the line.
|
|
132
|
+
|
|
133
|
+
## .secretignore
|
|
134
|
+
|
|
135
|
+
Create `.secretignore` in your project root to exclude paths:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
tests/fixtures/**
|
|
139
|
+
vendor/**
|
|
140
|
+
*.example
|
|
141
|
+
docs/
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Supports full `**` glob syntax (like `.gitignore`).
|
|
145
|
+
|
|
146
|
+
## GitHub Actions
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
- name: Scan for secrets
|
|
150
|
+
run: secrets scan . --severity HIGH --no-entropy --format sarif --output results.sarif
|
|
151
|
+
|
|
152
|
+
- name: Upload SARIF
|
|
153
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
154
|
+
with:
|
|
155
|
+
sarif_file: results.sarif
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Severity levels
|
|
159
|
+
|
|
160
|
+
| Level | Examples |
|
|
161
|
+
|----------|----------|
|
|
162
|
+
| CRITICAL | Private keys (RSA/EC/PGP/OpenSSH/PKCS#8), AWS credentials, Azure storage keys |
|
|
163
|
+
| HIGH | GitHub/GitLab tokens, Stripe live keys, OpenAI/Anthropic keys, Slack tokens, npm/PyPI tokens, Telegram/Discord bots |
|
|
164
|
+
| MEDIUM | Generic API keys, hardcoded passwords, JWT tokens, database URLs, Stripe test keys |
|
|
165
|
+
| LOW | High-entropy strings (possible unknown secrets) |
|
|
166
|
+
|
|
167
|
+
## Why history scanning matters
|
|
168
|
+
|
|
169
|
+
Deleting a secret from your latest commit does **not** remove it from git history. Anyone who clones your repo can run `git log -p` and recover it. Most scanners miss this completely.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Find secrets that were committed at any point in the last year
|
|
173
|
+
secrets scan . --history --depth 1000 --since 2024-01-01
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Architecture
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
scanner/
|
|
180
|
+
cli.py entry point (click)
|
|
181
|
+
engine.py file walker, parallel scanner, git history, shared kernel
|
|
182
|
+
patterns.py 55+ regex patterns
|
|
183
|
+
entropy.py Shannon entropy scorer (quoted + unquoted values)
|
|
184
|
+
verifier.py live API verification (10 services)
|
|
185
|
+
baseline.py save/load/compare baseline fingerprints
|
|
186
|
+
reporter.py terminal/JSON/CSV/SARIF/disclosure output
|
|
187
|
+
ignorefile.py .secretignore parser with ** glob support
|
|
188
|
+
github/
|
|
189
|
+
fetcher.py GitHub API client: repos, gists, commit history
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Contributing
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git clone https://github.com/Vasishta03/secret-scanner
|
|
196
|
+
cd secret-scanner
|
|
197
|
+
pip install -e ".[dev]"
|
|
198
|
+
pytest tests/
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
To add a pattern: edit `scanner/patterns.py` and add a test in `tests/test_scanner.py`.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
leakscan.egg-info/PKG-INFO
|
|
4
|
+
leakscan.egg-info/SOURCES.txt
|
|
5
|
+
leakscan.egg-info/dependency_links.txt
|
|
6
|
+
leakscan.egg-info/entry_points.txt
|
|
7
|
+
leakscan.egg-info/requires.txt
|
|
8
|
+
leakscan.egg-info/top_level.txt
|
|
9
|
+
scanner/__init__.py
|
|
10
|
+
scanner/baseline.py
|
|
11
|
+
scanner/cli.py
|
|
12
|
+
scanner/engine.py
|
|
13
|
+
scanner/entropy.py
|
|
14
|
+
scanner/ignorefile.py
|
|
15
|
+
scanner/patterns.py
|
|
16
|
+
scanner/reporter.py
|
|
17
|
+
scanner/verifier.py
|
|
18
|
+
scanner/github/__init__.py
|
|
19
|
+
scanner/github/fetcher.py
|
|
20
|
+
tests/test_scanner.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
scanner
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "leakscan"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "CLI tool to detect leaked secrets and API keys in codebases and public GitHub repos — including git history"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"click>=8.1",
|
|
14
|
+
"rich>=13.0",
|
|
15
|
+
"requests>=2.31",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
secrets = "scanner.cli:cli"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
dev = ["pytest>=7.0", "pytest-cov"]
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["."]
|
|
26
|
+
include = ["scanner*"]
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from scanner.engine import Finding, ScanResult
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def save(result: ScanResult, path: Path) -> None:
|
|
10
|
+
data = {
|
|
11
|
+
"version": 1,
|
|
12
|
+
"fingerprints": [f.fingerprint() for f in result.findings],
|
|
13
|
+
}
|
|
14
|
+
path.write_text(json.dumps(data, indent=2), encoding="utf-8")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def load(path: Path) -> set[str]:
|
|
18
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
19
|
+
return set(data.get("fingerprints", []))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def filter_new(findings: list[Finding], baseline: set[str]) -> list[Finding]:
|
|
23
|
+
return [f for f in findings if f.fingerprint() not in baseline]
|