vulntriage 0.12.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.
Files changed (42) hide show
  1. vulntriage-0.12.0/.env.example +21 -0
  2. vulntriage-0.12.0/.gitignore +53 -0
  3. vulntriage-0.12.0/.python-version +1 -0
  4. vulntriage-0.12.0/LICENSE +21 -0
  5. vulntriage-0.12.0/PKG-INFO +292 -0
  6. vulntriage-0.12.0/README.md +261 -0
  7. vulntriage-0.12.0/pyproject.toml +56 -0
  8. vulntriage-0.12.0/src/vulntriage/__init__.py +1 -0
  9. vulntriage-0.12.0/src/vulntriage/audit.py +85 -0
  10. vulntriage-0.12.0/src/vulntriage/cache.py +39 -0
  11. vulntriage-0.12.0/src/vulntriage/cli.py +447 -0
  12. vulntriage-0.12.0/src/vulntriage/context.py +134 -0
  13. vulntriage-0.12.0/src/vulntriage/epss.py +59 -0
  14. vulntriage-0.12.0/src/vulntriage/exceptions.py +18 -0
  15. vulntriage-0.12.0/src/vulntriage/ignore.py +17 -0
  16. vulntriage-0.12.0/src/vulntriage/importscan.py +83 -0
  17. vulntriage-0.12.0/src/vulntriage/kev.py +27 -0
  18. vulntriage-0.12.0/src/vulntriage/models.py +55 -0
  19. vulntriage-0.12.0/src/vulntriage/nvd.py +90 -0
  20. vulntriage-0.12.0/src/vulntriage/output.py +150 -0
  21. vulntriage-0.12.0/src/vulntriage/pypi.py +91 -0
  22. vulntriage-0.12.0/src/vulntriage/ranker.py +495 -0
  23. vulntriage-0.12.0/src/vulntriage/sarif.py +148 -0
  24. vulntriage-0.12.0/tests/__init__.py +0 -0
  25. vulntriage-0.12.0/tests/conftest.py +20 -0
  26. vulntriage-0.12.0/tests/fixtures/pip_audit_output.json +29 -0
  27. vulntriage-0.12.0/tests/fixtures/pyproject_sample.toml +8 -0
  28. vulntriage-0.12.0/tests/fixtures/requirements.txt +5 -0
  29. vulntriage-0.12.0/tests/test_audit.py +319 -0
  30. vulntriage-0.12.0/tests/test_cache.py +82 -0
  31. vulntriage-0.12.0/tests/test_cli.py +865 -0
  32. vulntriage-0.12.0/tests/test_context.py +166 -0
  33. vulntriage-0.12.0/tests/test_epss.py +94 -0
  34. vulntriage-0.12.0/tests/test_ignore.py +35 -0
  35. vulntriage-0.12.0/tests/test_importscan.py +70 -0
  36. vulntriage-0.12.0/tests/test_kev.py +81 -0
  37. vulntriage-0.12.0/tests/test_models.py +106 -0
  38. vulntriage-0.12.0/tests/test_nvd.py +197 -0
  39. vulntriage-0.12.0/tests/test_output.py +201 -0
  40. vulntriage-0.12.0/tests/test_pypi.py +92 -0
  41. vulntriage-0.12.0/tests/test_ranker.py +1109 -0
  42. vulntriage-0.12.0/tests/test_sarif.py +199 -0
@@ -0,0 +1,21 @@
1
+ # Provider selection (default: anthropic)
2
+ # Valid values: anthropic, openai, gemini, ollama
3
+ VULNTRIAGE_PROVIDER=anthropic
4
+
5
+ # Anthropic — default provider
6
+ # Get a key at https://console.anthropic.com
7
+ ANTHROPIC_API_KEY=sk-ant-...
8
+
9
+ # OpenAI (optional, requires: pip install 'vulntriage[openai]')
10
+ # Get a key at https://platform.openai.com/api-keys
11
+ OPENAI_API_KEY=sk-...
12
+
13
+ # Google Gemini (optional, requires: pip install 'vulntriage[gemini]')
14
+ # Free tier available at https://aistudio.google.com/apikey
15
+ GOOGLE_API_KEY=AIza...
16
+
17
+ # Ollama — local/offline (optional, requires: pip install 'vulntriage[ollama]')
18
+ # Model to use (default: llama3.2)
19
+ OLLAMA_MODEL=llama3.2
20
+ # Ollama server URL (default: http://localhost:11434)
21
+ OLLAMA_HOST=http://localhost:11434
@@ -0,0 +1,53 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ *.egg
6
+ .eggs/
7
+ dist/
8
+ build/
9
+ .venv/
10
+ venv/
11
+ .Python
12
+ pip-wheel-metadata/
13
+
14
+ # Coverage
15
+ .coverage
16
+ htmlcov/
17
+ .pytest_cache/
18
+
19
+ # Environment
20
+ .env
21
+ *.env
22
+
23
+ # Editor
24
+ .idea/
25
+ .vscode/
26
+ *.swp
27
+ *.swo
28
+
29
+ # OS
30
+ .DS_Store
31
+
32
+ # Internal / project-management artifacts — do not ship
33
+ CLAUDE.md
34
+ CLAUDE.md.bak
35
+ project.md
36
+ docs/
37
+
38
+ # Claude Code / ruflo / swarm session artifacts
39
+ .claude/
40
+ .claude.bak/
41
+ .claude-flow/
42
+ .swarm/
43
+ .mcp.json
44
+ ruvector.db
45
+ *.db-shm
46
+ *.db-wal
47
+
48
+ # Tool caches
49
+ .ruff_cache/
50
+ .mypy_cache/
51
+
52
+ # GBrain
53
+ .gbrain-source
@@ -0,0 +1 @@
1
+ 3.11.13
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vulntriage contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,292 @@
1
+ Metadata-Version: 2.4
2
+ Name: vulntriage
3
+ Version: 0.12.0
4
+ Summary: Rank pip-audit CVEs by real exploitability using Claude AI
5
+ Author: Nivish
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: ai,cve,pip-audit,security,vulnerability
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Topic :: Security
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: anthropic>=0.26.0
17
+ Requires-Dist: rich>=13.7.0
18
+ Requires-Dist: typer>=0.12.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: black>=24.0.0; extra == 'dev'
21
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
22
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
23
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
24
+ Provides-Extra: gemini
25
+ Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
26
+ Provides-Extra: ollama
27
+ Requires-Dist: ollama>=0.4.0; extra == 'ollama'
28
+ Provides-Extra: openai
29
+ Requires-Dist: openai>=1.0.0; extra == 'openai'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # vulntriage
33
+
34
+ Rank `pip-audit` CVEs by real exploitability using an LLM.
35
+
36
+ `pip-audit` reports every vulnerability your dependencies carry — but a CVSS 9.8 in a transitive dependency you never call is not the same risk as a CVSS 5.0 in your HTTP client that handles every request. `vulntriage` feeds your CVE list, your actual dependency stack, and authoritative threat intelligence (NVD CVSS, CISA KEV, EPSS) to an LLM, which ranks them by **real reachability** rather than raw severity score.
37
+
38
+ ---
39
+
40
+ ## Requirements
41
+
42
+ - Python 3.11+
43
+ - `pip-audit` installed and on `PATH` (`pip install pip-audit`)
44
+ - An Anthropic API key — or credentials for OpenAI, Gemini, or a local Ollama instance
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install vulntriage
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Usage
57
+
58
+ ```bash
59
+ export ANTHROPIC_API_KEY="sk-ant-..."
60
+
61
+ # Scan the current directory (needs requirements.txt or pyproject.toml)
62
+ vulntriage scan
63
+
64
+ # Scan a specific project
65
+ vulntriage scan --project-root /path/to/project
66
+
67
+ # Gate CI on CRITICAL only (not the default HIGH)
68
+ vulntriage scan --fail-on CRITICAL
69
+
70
+ # Save a timestamped JSON report
71
+ vulntriage scan --output-dir ./reports
72
+
73
+ # Skip all network fetches (use cached threat intel only)
74
+ vulntriage scan --offline
75
+
76
+ # Output machine-readable JSON (status messages go to stderr)
77
+ vulntriage scan --format json
78
+ ```
79
+
80
+ ### Flags
81
+
82
+ | Flag | Default | Description |
83
+ |---|---|---|
84
+ | `--project-root / -p` | `.` | Directory containing `requirements.txt` or `pyproject.toml` |
85
+ | `--fail-on` | `HIGH` | Exit 1 if any CVE at or above this severity: `CRITICAL / HIGH / MEDIUM / LOW / INFO` |
86
+ | `--format / -f` | `table` | Output format: `table` (Rich) or `json` (pipe-safe) |
87
+ | `--output-dir` | — | Save a timestamped JSON report to this directory after each scan |
88
+ | `--offline` | — | Skip all external API calls; use cached threat intel only |
89
+
90
+ ---
91
+
92
+ ### Output
93
+
94
+ ```
95
+ ╭─────────────────────────────────────────────────────────────╮
96
+ │ vulntriage — CVE Priority Report │
97
+ ├───┬──────────────────────┬──────────────────┬──────┬──────┬───────┬───────────────────────────────────┬──────────────────────────────┬──────────────────────────────────╮
98
+ │ # │ CVE / PYSEC ID │ Package │ Risk │ CVSS │ EPSS │ Reasoning │ Breaking Changes │ Fix │
99
+ ├───┼──────────────────────┼──────────────────┼──────┼──────┼───────┼───────────────────────────────────┼──────────────────────────────┼──────────────────────────────────┤
100
+ │ 1 │ CVE-2024-35195 │ requests 2.31.0 │ HIGH │ 9.1 │ 12.3% │ SSRF via proxied requests; direct │ verify=True is now the │ pip install requests>=2.32.0 │
101
+ │ │ ★ CISA KEV │ → 2.32.0 │ │ │ │ dep called at every API boundary │ default—audit any verify=False │ │
102
+ ├───┼──────────────────────┼──────────────────┼──────┼──────┼───────┼───────────────────────────────────┼──────────────────────────────┼──────────────────────────────────┤
103
+ │ 2 │ CVE-2022-40897 │ setuptools 65.5.0│ LOW │ 7.5 │ 0.1% │ ReDoS in package metadata parser; │ No breaking changes in patch │ pip install setuptools>=65.5.1 │
104
+ │ │ │ → 65.5.1 │ │ │ │ not reachable at app runtime │ release │ │
105
+ ╰───┴──────────────────────┴──────────────────┴──────┴──────┴───────┴───────────────────────────────────┴──────────────────────────────┴──────────────────────────────────╯
106
+ ```
107
+
108
+ `★ CISA KEV` — CISA has confirmed this CVE is actively exploited in the wild.
109
+
110
+ ---
111
+
112
+ ## Threat Intelligence
113
+
114
+ Before the LLM call, `vulntriage` fetches authoritative threat data from three public feeds and injects it into the prompt:
115
+
116
+ | Feed | What it provides | Rate limit |
117
+ |---|---|---|
118
+ | [NVD REST API v2](https://nvd.nist.gov/developers/vulnerabilities) | CVSS v3.1/v3.0/v2 base score per CVE | 5 req/30s free; 50 req/30s with `NVD_API_KEY` |
119
+ | [CISA KEV catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) | Whether each CVE is actively exploited in the wild | Single request, no key needed |
120
+ | [FIRST EPSS API](https://www.first.org/epss) | Exploitation probability percentage | Batch request, no key needed |
121
+
122
+ All three are cached at `~/.cache/vulntriage/` with a 24-hour TTL. The first scan pays the network cost; subsequent scans are instant.
123
+
124
+ **NVD scores are authoritative.** The NVD CVSS value always overrides whatever score the LLM returns.
125
+
126
+ ### Speeding up NVD fetches
127
+
128
+ Without an NVD API key, the tool pauses 6.1 seconds between CVE lookups to stay under the public rate limit. With a key, the pause drops to 0.7 seconds — significant for projects with many CVEs.
129
+
130
+ ```bash
131
+ # Get a free key at https://nvd.nist.gov/developers/request-an-api-key
132
+ export NVD_API_KEY="your-key-here"
133
+ vulntriage scan
134
+ ```
135
+
136
+ ### Offline mode
137
+
138
+ ```bash
139
+ # Skip all three feeds; use whatever is in the local cache
140
+ vulntriage scan --offline
141
+ ```
142
+
143
+ Use `--offline` in air-gapped environments or when deterministic scan time matters. The scan proceeds without threat intel if the cache is empty — CVSS, KEV, and EPSS fields are simply absent from the prompt.
144
+
145
+ ---
146
+
147
+ ## Suppressing CVEs
148
+
149
+ Create a `.vulnignore` file in your project root to suppress CVEs your team has reviewed and accepted:
150
+
151
+ ```
152
+ # Accepted — only reachable in development scripts, not at runtime
153
+ CVE-2022-40897
154
+
155
+ # Reviewed and accepted
156
+ CVE-2023-32681 Not reachable via our API surface — verified 2024-01-15
157
+ ```
158
+
159
+ Lines starting with `#` are comments. Text after the CVE ID is treated as a reason and ignored by the tool. Suppressed CVEs are excluded before the LLM call and do not count toward the exit code.
160
+
161
+ ---
162
+
163
+ ## Provider Selection
164
+
165
+ `vulntriage` supports four LLM backends. Set `VULNTRIAGE_PROVIDER` to switch:
166
+
167
+ | Provider | Env var | Install extra | Default model |
168
+ |---|---|---|---|
169
+ | `anthropic` (default) | `ANTHROPIC_API_KEY` | — | `claude-sonnet-4-6` |
170
+ | `openai` | `OPENAI_API_KEY` | `pip install 'vulntriage[openai]'` | `gpt-4o-mini` |
171
+ | `gemini` | `GOOGLE_API_KEY` | `pip install 'vulntriage[gemini]'` | `gemini-2.0-flash` |
172
+ | `ollama` | — | `pip install 'vulntriage[ollama]'` | `llama3.2` |
173
+
174
+ ```bash
175
+ # Use Gemini (free tier at aistudio.google.com/apikey)
176
+ export VULNTRIAGE_PROVIDER=gemini
177
+ export GOOGLE_API_KEY="AIza..."
178
+ vulntriage scan
179
+
180
+ # Use Ollama — fully local, no dependency data leaves your machine
181
+ export VULNTRIAGE_PROVIDER=ollama
182
+ vulntriage scan
183
+ ```
184
+
185
+ **Privacy note:** All providers except Ollama send your dependency names to an external API. If your dependency list is sensitive, use `VULNTRIAGE_PROVIDER=ollama`.
186
+
187
+ ### Ollama quickstart
188
+
189
+ ```bash
190
+ brew install ollama
191
+ ollama pull llama3.2
192
+ pip install 'vulntriage[ollama]'
193
+ VULNTRIAGE_PROVIDER=ollama vulntriage scan
194
+ ```
195
+
196
+ By default Ollama connects to `http://localhost:11434`. Override with `OLLAMA_HOST`. Use a different model with `OLLAMA_MODEL` (e.g. `OLLAMA_MODEL=mistral`). If the Ollama server is not running, `vulntriage` will start it automatically.
197
+
198
+ ---
199
+
200
+ ## CI Integration
201
+
202
+ `vulntriage scan` exits **1** if any CVE is ranked at or above `--fail-on` (default: `HIGH`), and **0** otherwise.
203
+
204
+ ### GitHub Actions
205
+
206
+ ```yaml
207
+ - name: Audit CVEs
208
+ env:
209
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
210
+ NVD_API_KEY: ${{ secrets.NVD_API_KEY }} # optional but speeds up NVD lookups
211
+ run: |
212
+ pip install pip-audit vulntriage
213
+ vulntriage scan --fail-on HIGH
214
+ ```
215
+
216
+ Gate on CRITICAL only:
217
+
218
+ ```yaml
219
+ vulntriage scan --fail-on CRITICAL
220
+ ```
221
+
222
+ Save a report as a CI artifact:
223
+
224
+ ```yaml
225
+ vulntriage scan --output-dir ./reports --format json
226
+ ```
227
+
228
+ ### GitLab CI
229
+
230
+ ```yaml
231
+ audit:
232
+ script:
233
+ - pip install pip-audit vulntriage
234
+ - vulntriage scan --fail-on HIGH
235
+ variables:
236
+ ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
237
+ NVD_API_KEY: $NVD_API_KEY
238
+ ```
239
+
240
+ ---
241
+
242
+ ## How it works
243
+
244
+ 1. Runs `pip-audit --format json` as a subprocess
245
+ 2. Reads `requirements.txt` or `pyproject.toml` to understand your actual stack
246
+ 3. Loads `.vulnignore` and removes suppressed CVEs
247
+ 4. Fetches threat intelligence from NVD, CISA KEV, and EPSS (skipped with `--offline`; all three cached 24h at `~/.cache/vulntriage/`)
248
+ 5. Sends the enriched CVE list and stack context to the configured LLM
249
+ 6. NVD CVSS overrides any score the LLM returns
250
+ 7. Renders a ranked Rich table or JSON output
251
+ 8. Exits 1 if any CVE is at or above `--fail-on` severity
252
+
253
+ LLM reasoning example:
254
+
255
+ > *"requests is a direct dependency called at every API boundary — HIGH (SSRF via proxied requests). setuptools is not reachable at application runtime — LOW despite CVSS 7.5."*
256
+
257
+ ---
258
+
259
+ ## Cost
260
+
261
+ Each scan makes one LLM API call. At `claude-sonnet-4-6` pricing (~$3/M input, $15/M output), a typical scan with 5–10 CVEs costs roughly **$0.004–0.01**. The static system prompt is cached across repeat scans (Anthropic 5-min TTL), cutting cost on subsequent runs by ~80%.
262
+
263
+ ---
264
+
265
+ ## Scope
266
+
267
+ - pip only (no npm, cargo, etc.)
268
+ - Context from `requirements.txt` / `pyproject.toml` — no static call-graph analysis
269
+ - Threat intel cached at `~/.cache/vulntriage/` with a 24-hour TTL
270
+
271
+ ---
272
+
273
+ ## Development
274
+
275
+ ```bash
276
+ git clone https://github.com/Nivish-21/Vuln
277
+ cd Vuln
278
+ python -m venv .venv && source .venv/bin/activate
279
+ pip install -e ".[dev]"
280
+
281
+ # Run tests
282
+ pytest
283
+
284
+ # Lint + format
285
+ black . && ruff check .
286
+ ```
287
+
288
+ ---
289
+
290
+ ## License
291
+
292
+ MIT
@@ -0,0 +1,261 @@
1
+ # vulntriage
2
+
3
+ Rank `pip-audit` CVEs by real exploitability using an LLM.
4
+
5
+ `pip-audit` reports every vulnerability your dependencies carry — but a CVSS 9.8 in a transitive dependency you never call is not the same risk as a CVSS 5.0 in your HTTP client that handles every request. `vulntriage` feeds your CVE list, your actual dependency stack, and authoritative threat intelligence (NVD CVSS, CISA KEV, EPSS) to an LLM, which ranks them by **real reachability** rather than raw severity score.
6
+
7
+ ---
8
+
9
+ ## Requirements
10
+
11
+ - Python 3.11+
12
+ - `pip-audit` installed and on `PATH` (`pip install pip-audit`)
13
+ - An Anthropic API key — or credentials for OpenAI, Gemini, or a local Ollama instance
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install vulntriage
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Usage
26
+
27
+ ```bash
28
+ export ANTHROPIC_API_KEY="sk-ant-..."
29
+
30
+ # Scan the current directory (needs requirements.txt or pyproject.toml)
31
+ vulntriage scan
32
+
33
+ # Scan a specific project
34
+ vulntriage scan --project-root /path/to/project
35
+
36
+ # Gate CI on CRITICAL only (not the default HIGH)
37
+ vulntriage scan --fail-on CRITICAL
38
+
39
+ # Save a timestamped JSON report
40
+ vulntriage scan --output-dir ./reports
41
+
42
+ # Skip all network fetches (use cached threat intel only)
43
+ vulntriage scan --offline
44
+
45
+ # Output machine-readable JSON (status messages go to stderr)
46
+ vulntriage scan --format json
47
+ ```
48
+
49
+ ### Flags
50
+
51
+ | Flag | Default | Description |
52
+ |---|---|---|
53
+ | `--project-root / -p` | `.` | Directory containing `requirements.txt` or `pyproject.toml` |
54
+ | `--fail-on` | `HIGH` | Exit 1 if any CVE at or above this severity: `CRITICAL / HIGH / MEDIUM / LOW / INFO` |
55
+ | `--format / -f` | `table` | Output format: `table` (Rich) or `json` (pipe-safe) |
56
+ | `--output-dir` | — | Save a timestamped JSON report to this directory after each scan |
57
+ | `--offline` | — | Skip all external API calls; use cached threat intel only |
58
+
59
+ ---
60
+
61
+ ### Output
62
+
63
+ ```
64
+ ╭─────────────────────────────────────────────────────────────╮
65
+ │ vulntriage — CVE Priority Report │
66
+ ├───┬──────────────────────┬──────────────────┬──────┬──────┬───────┬───────────────────────────────────┬──────────────────────────────┬──────────────────────────────────╮
67
+ │ # │ CVE / PYSEC ID │ Package │ Risk │ CVSS │ EPSS │ Reasoning │ Breaking Changes │ Fix │
68
+ ├───┼──────────────────────┼──────────────────┼──────┼──────┼───────┼───────────────────────────────────┼──────────────────────────────┼──────────────────────────────────┤
69
+ │ 1 │ CVE-2024-35195 │ requests 2.31.0 │ HIGH │ 9.1 │ 12.3% │ SSRF via proxied requests; direct │ verify=True is now the │ pip install requests>=2.32.0 │
70
+ │ │ ★ CISA KEV │ → 2.32.0 │ │ │ │ dep called at every API boundary │ default—audit any verify=False │ │
71
+ ├───┼──────────────────────┼──────────────────┼──────┼──────┼───────┼───────────────────────────────────┼──────────────────────────────┼──────────────────────────────────┤
72
+ │ 2 │ CVE-2022-40897 │ setuptools 65.5.0│ LOW │ 7.5 │ 0.1% │ ReDoS in package metadata parser; │ No breaking changes in patch │ pip install setuptools>=65.5.1 │
73
+ │ │ │ → 65.5.1 │ │ │ │ not reachable at app runtime │ release │ │
74
+ ╰───┴──────────────────────┴──────────────────┴──────┴──────┴───────┴───────────────────────────────────┴──────────────────────────────┴──────────────────────────────────╯
75
+ ```
76
+
77
+ `★ CISA KEV` — CISA has confirmed this CVE is actively exploited in the wild.
78
+
79
+ ---
80
+
81
+ ## Threat Intelligence
82
+
83
+ Before the LLM call, `vulntriage` fetches authoritative threat data from three public feeds and injects it into the prompt:
84
+
85
+ | Feed | What it provides | Rate limit |
86
+ |---|---|---|
87
+ | [NVD REST API v2](https://nvd.nist.gov/developers/vulnerabilities) | CVSS v3.1/v3.0/v2 base score per CVE | 5 req/30s free; 50 req/30s with `NVD_API_KEY` |
88
+ | [CISA KEV catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) | Whether each CVE is actively exploited in the wild | Single request, no key needed |
89
+ | [FIRST EPSS API](https://www.first.org/epss) | Exploitation probability percentage | Batch request, no key needed |
90
+
91
+ All three are cached at `~/.cache/vulntriage/` with a 24-hour TTL. The first scan pays the network cost; subsequent scans are instant.
92
+
93
+ **NVD scores are authoritative.** The NVD CVSS value always overrides whatever score the LLM returns.
94
+
95
+ ### Speeding up NVD fetches
96
+
97
+ Without an NVD API key, the tool pauses 6.1 seconds between CVE lookups to stay under the public rate limit. With a key, the pause drops to 0.7 seconds — significant for projects with many CVEs.
98
+
99
+ ```bash
100
+ # Get a free key at https://nvd.nist.gov/developers/request-an-api-key
101
+ export NVD_API_KEY="your-key-here"
102
+ vulntriage scan
103
+ ```
104
+
105
+ ### Offline mode
106
+
107
+ ```bash
108
+ # Skip all three feeds; use whatever is in the local cache
109
+ vulntriage scan --offline
110
+ ```
111
+
112
+ Use `--offline` in air-gapped environments or when deterministic scan time matters. The scan proceeds without threat intel if the cache is empty — CVSS, KEV, and EPSS fields are simply absent from the prompt.
113
+
114
+ ---
115
+
116
+ ## Suppressing CVEs
117
+
118
+ Create a `.vulnignore` file in your project root to suppress CVEs your team has reviewed and accepted:
119
+
120
+ ```
121
+ # Accepted — only reachable in development scripts, not at runtime
122
+ CVE-2022-40897
123
+
124
+ # Reviewed and accepted
125
+ CVE-2023-32681 Not reachable via our API surface — verified 2024-01-15
126
+ ```
127
+
128
+ Lines starting with `#` are comments. Text after the CVE ID is treated as a reason and ignored by the tool. Suppressed CVEs are excluded before the LLM call and do not count toward the exit code.
129
+
130
+ ---
131
+
132
+ ## Provider Selection
133
+
134
+ `vulntriage` supports four LLM backends. Set `VULNTRIAGE_PROVIDER` to switch:
135
+
136
+ | Provider | Env var | Install extra | Default model |
137
+ |---|---|---|---|
138
+ | `anthropic` (default) | `ANTHROPIC_API_KEY` | — | `claude-sonnet-4-6` |
139
+ | `openai` | `OPENAI_API_KEY` | `pip install 'vulntriage[openai]'` | `gpt-4o-mini` |
140
+ | `gemini` | `GOOGLE_API_KEY` | `pip install 'vulntriage[gemini]'` | `gemini-2.0-flash` |
141
+ | `ollama` | — | `pip install 'vulntriage[ollama]'` | `llama3.2` |
142
+
143
+ ```bash
144
+ # Use Gemini (free tier at aistudio.google.com/apikey)
145
+ export VULNTRIAGE_PROVIDER=gemini
146
+ export GOOGLE_API_KEY="AIza..."
147
+ vulntriage scan
148
+
149
+ # Use Ollama — fully local, no dependency data leaves your machine
150
+ export VULNTRIAGE_PROVIDER=ollama
151
+ vulntriage scan
152
+ ```
153
+
154
+ **Privacy note:** All providers except Ollama send your dependency names to an external API. If your dependency list is sensitive, use `VULNTRIAGE_PROVIDER=ollama`.
155
+
156
+ ### Ollama quickstart
157
+
158
+ ```bash
159
+ brew install ollama
160
+ ollama pull llama3.2
161
+ pip install 'vulntriage[ollama]'
162
+ VULNTRIAGE_PROVIDER=ollama vulntriage scan
163
+ ```
164
+
165
+ By default Ollama connects to `http://localhost:11434`. Override with `OLLAMA_HOST`. Use a different model with `OLLAMA_MODEL` (e.g. `OLLAMA_MODEL=mistral`). If the Ollama server is not running, `vulntriage` will start it automatically.
166
+
167
+ ---
168
+
169
+ ## CI Integration
170
+
171
+ `vulntriage scan` exits **1** if any CVE is ranked at or above `--fail-on` (default: `HIGH`), and **0** otherwise.
172
+
173
+ ### GitHub Actions
174
+
175
+ ```yaml
176
+ - name: Audit CVEs
177
+ env:
178
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
179
+ NVD_API_KEY: ${{ secrets.NVD_API_KEY }} # optional but speeds up NVD lookups
180
+ run: |
181
+ pip install pip-audit vulntriage
182
+ vulntriage scan --fail-on HIGH
183
+ ```
184
+
185
+ Gate on CRITICAL only:
186
+
187
+ ```yaml
188
+ vulntriage scan --fail-on CRITICAL
189
+ ```
190
+
191
+ Save a report as a CI artifact:
192
+
193
+ ```yaml
194
+ vulntriage scan --output-dir ./reports --format json
195
+ ```
196
+
197
+ ### GitLab CI
198
+
199
+ ```yaml
200
+ audit:
201
+ script:
202
+ - pip install pip-audit vulntriage
203
+ - vulntriage scan --fail-on HIGH
204
+ variables:
205
+ ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
206
+ NVD_API_KEY: $NVD_API_KEY
207
+ ```
208
+
209
+ ---
210
+
211
+ ## How it works
212
+
213
+ 1. Runs `pip-audit --format json` as a subprocess
214
+ 2. Reads `requirements.txt` or `pyproject.toml` to understand your actual stack
215
+ 3. Loads `.vulnignore` and removes suppressed CVEs
216
+ 4. Fetches threat intelligence from NVD, CISA KEV, and EPSS (skipped with `--offline`; all three cached 24h at `~/.cache/vulntriage/`)
217
+ 5. Sends the enriched CVE list and stack context to the configured LLM
218
+ 6. NVD CVSS overrides any score the LLM returns
219
+ 7. Renders a ranked Rich table or JSON output
220
+ 8. Exits 1 if any CVE is at or above `--fail-on` severity
221
+
222
+ LLM reasoning example:
223
+
224
+ > *"requests is a direct dependency called at every API boundary — HIGH (SSRF via proxied requests). setuptools is not reachable at application runtime — LOW despite CVSS 7.5."*
225
+
226
+ ---
227
+
228
+ ## Cost
229
+
230
+ Each scan makes one LLM API call. At `claude-sonnet-4-6` pricing (~$3/M input, $15/M output), a typical scan with 5–10 CVEs costs roughly **$0.004–0.01**. The static system prompt is cached across repeat scans (Anthropic 5-min TTL), cutting cost on subsequent runs by ~80%.
231
+
232
+ ---
233
+
234
+ ## Scope
235
+
236
+ - pip only (no npm, cargo, etc.)
237
+ - Context from `requirements.txt` / `pyproject.toml` — no static call-graph analysis
238
+ - Threat intel cached at `~/.cache/vulntriage/` with a 24-hour TTL
239
+
240
+ ---
241
+
242
+ ## Development
243
+
244
+ ```bash
245
+ git clone https://github.com/Nivish-21/Vuln
246
+ cd Vuln
247
+ python -m venv .venv && source .venv/bin/activate
248
+ pip install -e ".[dev]"
249
+
250
+ # Run tests
251
+ pytest
252
+
253
+ # Lint + format
254
+ black . && ruff check .
255
+ ```
256
+
257
+ ---
258
+
259
+ ## License
260
+
261
+ MIT