Skip to content

Commit 2cae2fc

Browse files
gaodan-fangclaude
andauthored
fix(deps): bump litellm to >=1.84.0 to resolve 7 CVEs (#277)
* fix(deps): bump litellm to >=1.84.0 to resolve 7 CVEs Addresses CVE-2026-49468 (Critical), CVE-2026-42271 (Critical), CVE-2026-42208 (Critical), CVE-2026-47102 (High), CVE-2026-47101 (High), CVE-2026-40217 (High), CVE-2026-42203 (High). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ci): add automated CVE scanning with pip-audit and Dependabot - Add pip-audit job to check-code workflow to block PRs with known vulns - Add dependabot.yml for weekly dependency monitoring and auto-fix PRs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): only block PRs on critical CVEs, create issues for high+critical - pip-audit runs with JSON output and continue-on-error - Queries OSV API for CVSS severity of each finding - Fails build only for Critical (CVSS >= 9.0) vulnerabilities - Auto-creates/updates a GitHub issue listing High+Critical findings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): make CVE scan informational only, never block PRs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): harden check-vulnerabilities permissions and credential handling - Add explicit contents: read permission (least privilege) - Disable persist-credentials on checkout to avoid token leakage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6f2bfc0 commit 2cae2fc

5 files changed

Lines changed: 161 additions & 6 deletions

File tree

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
groups:
8+
security-patches:
9+
applies-to: security-updates

.github/workflows/check-code.yaml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,152 @@ jobs:
103103
- name: Verify platform-integrations matches a fresh render of plugin-source
104104
run: uv run python plugin-source/build_plugins.py check
105105

106+
check-vulnerabilities:
107+
runs-on: ubuntu-latest
108+
permissions:
109+
contents: read
110+
issues: write
111+
steps:
112+
- uses: actions/checkout@v5
113+
with:
114+
persist-credentials: false
115+
- name: Install uv
116+
uses: astral-sh/setup-uv@v6
117+
with:
118+
enable-cache: true
119+
python-version: '3.12'
120+
- name: Export requirements from lockfile
121+
run: uv export --no-hashes --frozen > /tmp/requirements.txt
122+
- name: Install pip-audit
123+
run: uv tool install pip-audit
124+
- name: Run pip-audit
125+
id: audit
126+
continue-on-error: true
127+
run: pip-audit -r /tmp/requirements.txt --format json --output /tmp/audit-results.json
128+
- name: Process results and gate on critical CVEs
129+
if: steps.audit.outcome == 'failure'
130+
uses: actions/github-script@v7
131+
with:
132+
script: |
133+
const fs = require('fs');
134+
const results = JSON.parse(fs.readFileSync('/tmp/audit-results.json', 'utf8'));
135+
136+
const vulns = [];
137+
for (const dep of results.dependencies || []) {
138+
for (const vuln of dep.vulns || []) {
139+
vulns.push({ name: dep.name, version: dep.version, id: vuln.id, fix_versions: vuln.fix_versions || [] });
140+
}
141+
}
142+
143+
if (vulns.length === 0) return;
144+
145+
// Query OSV API for severity of each unique vuln ID
146+
const uniqueIds = [...new Set(vulns.map(v => v.id))];
147+
const severityMap = {};
148+
149+
for (const id of uniqueIds) {
150+
try {
151+
const resp = await fetch(`https://api.osv.dev/v1/vulns/${id}`);
152+
if (!resp.ok) continue;
153+
const data = await resp.json();
154+
// Extract CVSS score from severity or database_specific
155+
let score = 0;
156+
if (data.severity && data.severity.length > 0) {
157+
for (const s of data.severity) {
158+
if (s.type === 'CVSS_V3' || s.type === 'CVSS_V4') {
159+
// Parse base score from vector — last metric group
160+
const match = s.score?.match(/CVSS:\d\.\d\/(.+)/);
161+
if (match) {
162+
// Use database_specific for numeric score if available
163+
}
164+
}
165+
}
166+
}
167+
// Check database_specific for numeric CVSS
168+
if (data.database_specific?.cvss_v3) {
169+
score = typeof data.database_specific.cvss_v3 === 'number'
170+
? data.database_specific.cvss_v3
171+
: parseFloat(data.database_specific.cvss_v3) || 0;
172+
}
173+
if (data.database_specific?.severity) {
174+
const sev = data.database_specific.severity.toUpperCase();
175+
if (sev === 'CRITICAL') score = Math.max(score, 9.0);
176+
else if (sev === 'HIGH') score = Math.max(score, 7.0);
177+
}
178+
// Fallback: check affected[].ecosystem_specific or aliases for NVD
179+
if (score === 0 && data.affected) {
180+
for (const a of data.affected) {
181+
if (a.database_specific?.cvss_v3) {
182+
score = Math.max(score, parseFloat(a.database_specific.cvss_v3) || 0);
183+
}
184+
}
185+
}
186+
severityMap[id] = score;
187+
} catch (e) {
188+
console.log(`Warning: could not fetch severity for ${id}`);
189+
severityMap[id] = 0;
190+
}
191+
}
192+
193+
// Categorize
194+
const critical = vulns.filter(v => (severityMap[v.id] || 0) >= 9.0);
195+
const high = vulns.filter(v => {
196+
const s = severityMap[v.id] || 0;
197+
return s >= 7.0 && s < 9.0;
198+
});
199+
200+
console.log(`Found ${critical.length} critical, ${high.length} high vulnerabilities`);
201+
202+
// Create/update GH issue for high+critical
203+
if (critical.length > 0 || high.length > 0) {
204+
const lines = ['## Automated CVE Scan Results\n', `_Last scanned: ${new Date().toISOString().split('T')[0]}_\n`];
205+
if (critical.length) {
206+
lines.push('### Critical (CVSS >= 9.0)\n');
207+
critical.forEach(v => lines.push(`- **${v.id}** in \`${v.name}==${v.version}\` — fix: ${v.fix_versions.join(', ') || 'none available'}`));
208+
}
209+
if (high.length) {
210+
lines.push('\n### High (CVSS >= 7.0)\n');
211+
high.forEach(v => lines.push(`- **${v.id}** in \`${v.name}==${v.version}\` — fix: ${v.fix_versions.join(', ') || 'none available'}`));
212+
}
213+
214+
const existing = await github.rest.issues.listForRepo({
215+
owner: context.repo.owner,
216+
repo: context.repo.repo,
217+
labels: 'security,automated',
218+
state: 'open'
219+
});
220+
221+
const title = `[Security] ${critical.length} critical, ${high.length} high vulnerabilities detected`;
222+
const existingIssue = existing.data.find(i => i.labels.some(l => l.name === 'automated'));
223+
224+
if (existingIssue) {
225+
await github.rest.issues.update({
226+
owner: context.repo.owner,
227+
repo: context.repo.repo,
228+
issue_number: existingIssue.number,
229+
title,
230+
body: lines.join('\n')
231+
});
232+
console.log(`Updated issue #${existingIssue.number}`);
233+
} else {
234+
await github.rest.issues.create({
235+
owner: context.repo.owner,
236+
repo: context.repo.repo,
237+
title,
238+
body: lines.join('\n'),
239+
labels: ['security', 'automated']
240+
});
241+
console.log('Created new security issue');
242+
}
243+
}
244+
245+
// Report but never block the build
246+
if (critical.length > 0) {
247+
core.warning(`${critical.length} critical CVEs found: ${critical.map(v => v.id).join(', ')} — tracked in GitHub issue`);
248+
} else {
249+
console.log('No critical vulnerabilities. High-severity issues tracked in GitHub issue.');
250+
}
251+
106252
ui-tests:
107253
runs-on: ubuntu-latest
108254
steps:

explorations/claudecode/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ readme = "README.md"
66
requires-python = ">=3.12"
77
dependencies = [
88
"arize-phoenix>=12.25.1",
9-
"litellm[proxy]>=1.80.10",
9+
"litellm[proxy]>=1.84.0",
1010
"opentelemetry-api>=1.39.1",
1111
"opentelemetry-exporter-otlp>=1.39.1",
1212
"opentelemetry-sdk>=1.39.1",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dependencies = [
88
"arize-phoenix>=12.30.0",
99
"fastmcp",
1010
"jinja2",
11-
"litellm",
11+
"litellm>=1.84.0",
1212
"pydantic",
1313
"sentence-transformers",
1414
"typer>=0.9.0",

uv.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)