diff --git a/.circleci/config.yml b/.circleci/config.yml index d4943b59c9a..307247651e7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ commands: # conflicts with transitive dep pins like openai<2 and pydantic>=2.11.5) pip install "pytest-mock==3.12.0" "pytest==7.3.1" "pytest-retry==1.6.3" \ "pytest-asyncio==0.21.1" "respx==0.22.0" "hypercorn==0.17.3" \ - "pydantic==2.11.0" "mcp==1.25.0" "requests-mock>=1.12.1" \ + "pydantic==2.12.5" "mcp==1.26.0" "requests-mock>=1.12.1" \ "responses==0.25.7" "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" \ "pytest-cov==5.0.0" "semantic_router==0.1.10" "fastapi-offline==1.7.3" \ "a2a" "parameterized>=0.9.0" @@ -150,16 +150,16 @@ jobs: python -m pip install --upgrade pip python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ - "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.43.0" pyarrow \ - "boto3==1.36.0" "aioboto3==13.4.0" langchain lunary==0.2.5 \ - "azure-identity==1.16.1" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ + "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ + "boto3==1.42.80" langchain lunary==0.2.5 \ + "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ - "gunicorn==21.2.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ - "apscheduler==3.10.4" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ - python-multipart prometheus-client==0.20.0 "pydantic==2.10.2" \ - "diskcache==5.6.1" "Pillow==10.3.0" "jsonschema==4.22.0" \ - "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==13.1.0" + "gunicorn==23.0.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ + "apscheduler==3.11.2" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ + python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ + "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ + "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -245,16 +245,16 @@ jobs: python -m pip install --upgrade pip python -m pip install -r .circleci/requirements.txt pip install "pytest==7.3.1" "pytest-retry==1.6.3" "pytest-asyncio==0.21.1" "pytest-cov==5.0.0" \ - "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.43.0" pyarrow \ - "boto3==1.36.0" "aioboto3==13.4.0" langchain lunary==0.2.5 \ - "azure-identity==1.16.1" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ + "mypy==1.18.2" "google-generativeai==0.3.2" "google-cloud-aiplatform==1.133.0" pyarrow \ + "boto3==1.42.80" langchain lunary==0.2.5 \ + "azure-identity==1.25.3" "langfuse==2.59.7" "logfire==0.29.0" numpydoc \ traceloop-sdk==0.21.1 openai==1.100.1 prisma==0.11.0 \ "detect_secrets==1.5.0" "respx==0.22.0" fastapi \ - "gunicorn==21.2.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ - "apscheduler==3.10.4" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ - python-multipart prometheus-client==0.20.0 "pydantic==2.10.2" \ - "diskcache==5.6.1" "Pillow==10.3.0" "jsonschema==4.22.0" \ - "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==13.1.0" + "gunicorn==23.0.0" "aiodynamo==23.10.1" "asyncio==3.4.3" \ + "apscheduler==3.11.2" "PyGithub==1.59.1" argon2-cffi "pytest-mock==3.12.0" \ + python-multipart prometheus-client==0.20.0 "pydantic==2.12.5" \ + "diskcache==5.6.1" "Pillow==12.1.1" "jsonschema==4.23.0" \ + "pytest-xdist==3.6.1" "pytest-timeout==2.2.0" "websockets==15.0.1" pip install semantic_router --no-deps pip install aurelio_sdk --no-deps pip uninstall posthog -y @@ -346,42 +346,41 @@ jobs: pip install "pytest-cov==5.0.0" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" pip install langchain pip install lunary==0.2.5 - pip install "azure-identity==1.16.1" + pip install "azure-identity==1.25.3" pip install "langfuse==2.59.7" pip install "logfire==0.29.0" pip install numpydoc pip install traceloop-sdk==0.21.1 - pip install opentelemetry-api==1.25.0 - pip install opentelemetry-sdk==1.25.0 - pip install opentelemetry-exporter-otlp==1.25.0 + pip install opentelemetry-api==1.28.0 + pip install opentelemetry-sdk==1.28.0 + pip install opentelemetry-exporter-otlp==1.28.0 pip install openai==1.100.1 pip install prisma==0.11.0 pip install "detect_secrets==1.5.0" - pip install "httpx==0.24.1" + pip install "httpx==0.28.1" pip install "respx==0.22.0" pip install fastapi - pip install "gunicorn==21.2.0" - pip install "anyio==4.2.0" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" - pip install "apscheduler==3.10.4" + pip install "apscheduler==3.11.2" pip install "PyGithub==1.59.1" pip install argon2-cffi pip install "pytest-mock==3.12.0" pip install python-multipart pip install google-cloud-aiplatform pip install prometheus-client==0.20.0 - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" pip install "diskcache==5.6.1" - pip install "Pillow==10.3.0" - pip install "jsonschema==4.22.0" - pip install "websockets==13.1.0" + pip install "Pillow==12.1.1" + pip install "jsonschema==4.23.0" + pip install "websockets==15.0.1" - setup_litellm_enterprise_pip - save_cache: paths: @@ -700,8 +699,8 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.11.0" - pip install "mcp==1.25.0" + pip install "pydantic==2.12.5" + pip install "mcp==1.26.0" pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -746,7 +745,7 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.11.0" + pip install "pydantic==2.12.5" pip install "a2a-sdk" # Run pytest and generate JUnit XML report - run: @@ -791,8 +790,8 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.10.2" - pip install "boto3==1.36.0" + pip install "pydantic==2.12.5" + pip install "boto3==1.42.80" pip install "semantic_router==0.1.10" --no-deps pip install aurelio_sdk pip install "pytest-xdist==3.6.1" @@ -841,7 +840,7 @@ jobs: pip install "pytest-cov==5.0.0" pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" # Run pytest and generate JUnit XML report - run: name: Run tests @@ -1048,8 +1047,8 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "respx==0.22.0" pip install "hypercorn==0.17.3" - pip install "pydantic==2.11.0" - pip install "mcp==1.25.0" + pip install "pydantic==2.12.5" + pip install "mcp==1.26.0" pip install "requests-mock>=1.12.1" pip install "responses==0.25.7" pip install "pytest-xdist==3.6.1" @@ -1090,7 +1089,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report - run: @@ -1137,7 +1136,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pytest-mock pip install "pytest-xdist==3.6.1" # Run pytest and generate JUnit XML report @@ -1259,9 +1258,9 @@ jobs: pip install pytest-mock pip install "respx==0.22.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install "mlflow==2.17.2" - pip install "anthropic==0.52.0" + pip install "anthropic==0.54.0" pip install "blockbuster==1.5.24" pip install "pytest-xdist==3.6.1" pip install "pytest-timeout==2.2.0" @@ -1352,11 +1351,11 @@ jobs: pip install aiohttp pip install openai pip install click - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install jinja2 - pip install "tokenizers==0.20.0" + pip install "tokenizers==0.22.2" pip install "uvloop==0.21.0" - pip install "fastuuid==0.12.0" + pip install "fastuuid==0.14.0" pip install jsonschema - setup_litellm_enterprise_pip - run: @@ -1389,7 +1388,7 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "pytest-cov==5.0.0" pip install "tomli==2.2.1" - pip install "mcp==1.25.0" + pip install "mcp==1.26.0" - run: name: Run tests command: | @@ -1679,10 +1678,9 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1690,9 +1688,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -1823,10 +1821,9 @@ jobs: pip install "mypy==1.18.2" pip install "jsonlines==4.0.0" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" pip install langchain pip install "langchain_mcp_adapters==0.0.5" pip install "langfuse>=2.0.0" @@ -1835,9 +1832,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -1969,10 +1966,9 @@ jobs: pip install "pytest-asyncio==0.21.1" pip install "mypy==1.18.2" pip install "google-generativeai==0.3.2" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install pyarrow - pip install "boto3==1.36.0" - pip install "aioboto3==13.4.0" + pip install "boto3==1.42.80" pip install langchain pip install "langfuse>=2.0.0" pip install "logfire==0.29.0" @@ -1980,9 +1976,9 @@ jobs: pip install prisma pip install fastapi pip install jsonschema - pip install "httpx==0.24.1" - pip install "gunicorn==21.2.0" - pip install "anyio==3.7.1" + pip install "httpx==0.28.1" + pip install "gunicorn==23.0.0" + pip install "anyio==4.8.0" pip install "aiodynamo==23.10.1" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" @@ -2611,16 +2607,16 @@ jobs: pip install "pytest==7.3.1" pip install "pytest-retry==1.6.3" pip install "pytest-asyncio==0.21.1" - pip install "google-cloud-aiplatform==1.43.0" + pip install "google-cloud-aiplatform==1.133.0" pip install aiohttp pip install "openai==1.100.1" pip install "assemblyai==0.37.0" python -m pip install --upgrade pip - pip install "pydantic==2.10.2" + pip install "pydantic==2.12.5" pip install "pytest==7.3.1" pip install "pytest-mock==3.12.0" pip install "pytest-asyncio==0.21.1" - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install "mypy==1.18.2" pip install pyarrow pip install numpydoc @@ -2628,11 +2624,11 @@ jobs: pip install fastapi pip install jsonschema pip install "httpx==0.27.0" - pip install "anyio==3.7.1" + pip install "anyio==4.8.0" pip install "asyncio==3.4.3" pip install "PyGithub==1.59.1" pip install "google-cloud-aiplatform==1.59.0" - pip install "anthropic==0.52.0" + pip install "anthropic==0.54.0" pip install "langchain_mcp_adapters==0.0.5" pip install "langchain_openai==0.2.1" pip install "langgraph==0.3.18" @@ -2799,7 +2795,7 @@ jobs: conda activate myenv pip install "pytest==7.3.1" pip install "pytest-asyncio==0.21.1" - pip install "boto3==1.36.0" + pip install "boto3==1.42.80" pip install "httpx==0.27.0" pip install "claude-agent-sdk" pip install -r requirements.txt @@ -3237,31 +3233,9 @@ jobs: name: Install Playwright Browsers command: | npx playwright install - - run: - name: Install Neon CLI - command: | - npm i -g neonctl - - run: - name: Create Neon branch - command: | - export EXPIRES_AT=$(date -u -d "+3 hours" +"%Y-%m-%dT%H:%M:%SZ") - echo "Expires at: $EXPIRES_AT" - neon branches create \ - --project-id $NEON_PROJECT_ID \ - --name preview/commit-${CIRCLE_SHA1:0:7}-<< parameters.browser >> \ - --expires-at $EXPIRES_AT \ - --parent br-fancy-paper-ad1olsb3 \ - --api-key $NEON_API_KEY || true - run: name: Run Docker container command: | - E2E_UI_TEST_DATABASE_URL=$(neon connection-string \ - --project-id $NEON_PROJECT_ID \ - --api-key $NEON_API_KEY \ - --branch preview/commit-${CIRCLE_SHA1:0:7}-<< parameters.browser >> \ - --database-name yuneng-trial-db \ - --role neondb_owner) - echo $E2E_UI_TEST_DATABASE_URL docker run -d \ -p 4000:4000 \ -e DATABASE_URL=$E2E_UI_TEST_DATABASE_URL \ @@ -3535,7 +3509,7 @@ workflows: only: - main - /litellm_.*/ - # - e2e_ui_testing: # migrate to dynamic db - currently requires neon cli + # - e2e_ui_testing: # name: e2e_ui_testing_chromium # browser: chromium # context: e2e_ui_tests diff --git a/.circleci/requirements.txt b/.circleci/requirements.txt index ab4c3995772..be12ab2d0f1 100644 --- a/.circleci/requirements.txt +++ b/.circleci/requirements.txt @@ -7,15 +7,15 @@ cohere redis==5.2.1 redisvl==0.4.1 anthropic -orjson==3.10.12 # fast /embedding responses -pydantic==2.11.0 -google-cloud-aiplatform==1.43.0 +orjson==3.10.15 # fast /embedding responses +pydantic==2.12.5 +google-cloud-aiplatform==1.133.0 google-cloud-iam==2.19.1 fastapi-sso==0.16.0 uvloop==0.21.0 -mcp==1.25.0 # for MCP server +mcp==1.26.0 # for MCP server semantic_router==0.1.10 # for auto-routing with litellm -fastuuid==0.12.0 +fastuuid==0.14.0 responses==0.25.7 # for proxy client tests pytest-retry==1.6.3 # for automatic test retries litellm-proxy-extras # for prisma migrations \ No newline at end of file diff --git a/.github/workflows/run_llm_translation_tests.py b/.github/workflows/run_llm_translation_tests.py old mode 100755 new mode 100644 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7cd12bb219c..3a00064c3bd 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,6 +42,6 @@ jobs: retention-days: 5 - name: Upload to code scanning - uses: github/codeql-action/upload-sarif@c10b806170c8ee63ea24152429041b5624f0baf5 # v4.35.1 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: sarif_file: results.sarif diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 2bc361bc48f..00000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,40 +0,0 @@ -repos: -- repo: local - hooks: - - id: pyright - name: pyright - entry: pyright - language: system - types: [python] - files: ^(litellm/|litellm_proxy_extras/|enterprise/) - - id: isort - name: isort - entry: isort - language: system - types: [python] - files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py - exclude: ^litellm/__init__.py$ - - id: black - name: black - entry: poetry run black - language: system - types: [python] - files: (litellm/|litellm_proxy_extras/).*\.py -- repo: https://github.com/pycqa/flake8 - rev: 7.0.0 # The version of flake8 to use - hooks: - - id: flake8 - exclude: ^litellm/tests/|^litellm/proxy/tests/|^litellm/tests/test_litellm/|^tests/test_litellm/|^tests/enterprise/ - additional_dependencies: [flake8-print] - files: (litellm/|litellm_proxy_extras/|enterprise/).*\.py -- repo: https://github.com/python-poetry/poetry - rev: 1.8.0 - hooks: - - id: poetry-check - files: ^(pyproject.toml|litellm-proxy-extras/pyproject.toml)$ -- repo: local - hooks: - - id: check-files-match - name: Check if files match - entry: python3 ci_cd/check_files_match.py - language: system \ No newline at end of file diff --git a/.trivyignore b/.trivyignore deleted file mode 100644 index 0d04ecacdb5..00000000000 --- a/.trivyignore +++ /dev/null @@ -1,12 +0,0 @@ -# LiteLLM Trivy Ignore File -# CVEs listed here are temporarily allowlisted pending fixes - -# Next.js vulnerabilities in UI dashboard (next@14.2.35) -# Allowlisted: 2026-01-31, 7-day fix timeline -# Fix: Upgrade to Next.js 15.5.10+ or 16.1.5+ - -# HIGH: DoS via request deserialization -GHSA-h25m-26qc-wcjf - -# MEDIUM: Image Optimizer DoS -CVE-2025-59471 diff --git a/ci_cd/.grype.yaml b/ci_cd/.grype.yaml deleted file mode 100644 index b9bc9db58f5..00000000000 --- a/ci_cd/.grype.yaml +++ /dev/null @@ -1,36 +0,0 @@ -ignore: - - vulnerability: CVE-2026-22184 - reason: no fixed zlib package is available yet in the Wolfi repositories, so this is ignored temporarily until an upstream release exists - # Wolfi base image: Python 3.13 and Node from apk have no fixed builds in Wolfi yet / not applicable - - vulnerability: CVE-2025-55130 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: CVE-2025-59465 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: CVE-2025-55131 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: CVE-2025-59466 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: CVE-2026-21637 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: CVE-2025-55132 - reason: Node in Wolfi apk; only used for Admin UI build/prisma - - vulnerability: GHSA-hx9q-6w63-j58v - reason: orjson dumps recursion; allowlisted - - vulnerability: GHSA-73rr-hh4g-fpgx - reason: diff npm transitive dep; override in package.json, allowlisted - - vulnerability: CVE-2026-0865 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2025-15282 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2026-0672 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2025-15366 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2025-15367 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2025-11468 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2025-12781 - reason: Python 3.13 in Wolfi base; no fixed apk build yet - - vulnerability: CVE-2026-1299 - reason: Python 3.13 in Wolfi base; no fixed apk build yet diff --git a/ci_cd/publish-proxy-extras.sh b/ci_cd/publish-proxy-extras.sh deleted file mode 100644 index 6c83d1f9212..00000000000 --- a/ci_cd/publish-proxy-extras.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Exit on error -set -e - -echo "🚀 Building and publishing litellm-proxy-extras" - -# Navigate to litellm-proxy-extras directory -cd "$(dirname "$0")/../litellm-proxy-extras" - -# Build the package -echo "📦 Building package..." -poetry build - -# Publish to PyPI -echo "🌎 Publishing to PyPI..." -poetry publish - -echo "✅ Done! Package published successfully" \ No newline at end of file diff --git a/ci_cd/security_scans.sh b/ci_cd/security_scans.sh deleted file mode 100755 index ee33393c8b1..00000000000 --- a/ci_cd/security_scans.sh +++ /dev/null @@ -1,262 +0,0 @@ -#!/bin/bash - -# Security Scans Script for LiteLLM -# This script runs comprehensive security scans including Trivy and Grype - -set -e - -echo "Starting security scans for LiteLLM..." - -# Function to install Trivy and required tools -install_trivy() { - echo "Installing Trivy and required tools..." - TRIVY_VERSION="0.35.0" - sudo apt-get update - sudo apt-get install -y wget jq curl bsdmainutils - wget -qO trivy.deb "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.deb" - sudo dpkg -i trivy.deb - rm trivy.deb - echo "Trivy ${TRIVY_VERSION} installed successfully" -} - -# Function to install Grype -install_grype() { - echo "Installing Grype..." - curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sudo sh -s -- -b /usr/local/bin - echo "Grype installed successfully" -} - -# Function to install ggshield -install_ggshield() { - echo "Installing ggshield..." - pip3 install --upgrade pip - pip3 install ggshield - echo "ggshield installed successfully" -} - -# # Function to run secret detection scans -# run_secret_detection() { -# echo "Running secret detection scans..." - -# if ! command -v ggshield &> /dev/null; then -# install_ggshield -# fi - -# # Check if GITGUARDIAN_API_KEY is set (required for CI/CD) -# if [ -z "$GITGUARDIAN_API_KEY" ]; then -# echo "Warning: GITGUARDIAN_API_KEY environment variable is not set." -# echo "ggshield requires a GitGuardian API key to scan for secrets." -# echo "Please set GITGUARDIAN_API_KEY in your CI/CD environment variables." -# exit 1 -# fi - -# echo "Scanning codebase for secrets..." -# echo "Note: Large codebases may take several minutes due to API rate limits (50 requests/minute on free plan)" -# echo "ggshield will automatically handle rate limits and retry as needed." -# echo "Binary files, cache files, and build artifacts are excluded via .gitguardian.yaml" - -# # Use --recursive for directory scanning and auto-confirm if prompted -# # .gitguardian.yaml will automatically exclude binary files, wheel files, etc. -# # GITGUARDIAN_API_KEY environment variable will be used for authentication -# echo y | ggshield secret scan path . --recursive || { -# echo "" -# echo "==========================================" -# echo "ERROR: Secret Detection Failed" -# echo "==========================================" -# echo "ggshield has detected secrets in the codebase." -# echo "Please review discovered secrets above, revoke any actively used secrets" -# echo "from underlying systems and make changes to inject secrets dynamically at runtime." -# echo "" -# echo "For more information, see: https://docs.gitguardian.com/secrets-detection/" -# echo "==========================================" -# echo "" -# exit 1 -# } - -# echo "Secret detection scans completed successfully" -# } - -# Function to run Trivy scans -run_trivy_scans() { - echo "Running Trivy scans..." - - echo "Scanning LiteLLM Docs..." - trivy fs --ignorefile .trivyignore --scanners vuln --dependency-tree --exit-code 1 --severity HIGH,CRITICAL,MEDIUM ./docs/ - - echo "Scanning LiteLLM UI..." - trivy fs --ignorefile .trivyignore --scanners vuln --dependency-tree --exit-code 1 --severity HIGH,CRITICAL,MEDIUM ./ui/ - - echo "Trivy scans completed successfully" -} - -# Function to build and scan Docker images with Grype -run_grype_scans() { - echo "Running Grype scans..." - - # Temporarily add wheel files to .dockerignore for security scans - echo "Temporarily modifying .dockerignore to exclude problematic wheel files..." - cp .dockerignore .dockerignore.backup 2>/dev/null || touch .dockerignore.backup - echo "/*.whl" >> .dockerignore - - # Build and scan Dockerfile.database - echo "Building and scanning Dockerfile.database..." - docker build --no-cache -t litellm-database:latest -f ./docker/Dockerfile.database . - grype litellm-database:latest --config ci_cd/.grype.yaml --fail-on critical - - # Build and scan main Dockerfile - echo "Building and scanning main Dockerfile..." - docker build --no-cache -t litellm:latest . - grype litellm:latest --config ci_cd/.grype.yaml --fail-on critical - - # Restore original .dockerignore - echo "Restoring original .dockerignore..." - mv .dockerignore.backup .dockerignore - - # Scan the locally built LiteLLM image for vulnerabilities with CVSS >= 4.0 - echo "Scanning locally built LiteLLM image for high-severity vulnerabilities..." - echo "Using locally built image: litellm:latest" - - # Allowlist of CVEs to be ignored in failure threshold/reporting - # - CVE-2025-8869: Not applicable on Python >=3.13 (PEP 706 implemented); pip fallback unused; no OS-level fix - # - GHSA-4xh5-x5gv-qwph: GitHub Security Advisory alias for CVE-2025-8869 - # - GHSA-5j98-mcp5-4vw2: glob CLI command injection via -c/--cmd; glob CLI is not used in the litellm runtime image, - # and the vulnerable versions are pulled in only via OS-level/node tooling outside of our application code - ALLOWED_CVES=( - "CVE-2025-8869" - "GHSA-4xh5-x5gv-qwph" - "CVE-2025-8291" # no fix available as of Oct 11, 2025 - "GHSA-5j98-mcp5-4vw2" - "CVE-2025-13836" # Python 3.13 HTTP response reading OOM/DoS - no fix available in base image - "CVE-2025-12084" # Python 3.13 xml.dom.minidom quadratic algorithm - no fix available in base image - "CVE-2025-60876" # BusyBox wget HTTP request splitting - no fix available in Chainguard Wolfi base image - "CVE-2026-0861" # Wolfi glibc still flagged even on 2.42-r5; upstream patched build unavailable yet - "CVE-2010-4756" # glibc glob DoS - awaiting patched Wolfi glibc build - "CVE-2019-1010022" # glibc stack guard bypass - awaiting patched Wolfi glibc build - "CVE-2019-1010023" # glibc ldd remap issue - awaiting patched Wolfi glibc build - "CVE-2019-1010024" # glibc ASLR mitigation bypass - awaiting patched Wolfi glibc build - "CVE-2019-1010025" # glibc pthread heap address leak - awaiting patched Wolfi glibc build - "CVE-2026-22184" # zlib untgz buffer overflow - untgz unused + no fixed Wolfi build yet - "GHSA-58pv-8j8x-9vj2" # jaraco.context path traversal - setuptools vendored only (v5.3.0), not used in application code (using v6.1.0+) - "GHSA-34x7-hfp2-rc4v" # node-tar hardlink path traversal - not applicable, tar CLI not exposed in application code - "GHSA-r6q2-hw4h-h46w" # node-tar not used by application runtime, Linux-only container, not affect by macOS APFS-specific exploit - "GHSA-8rrh-rw8j-w5fx" # wheel is from chainguard and will be handled by then TODO: Remove this after Chainguard updates the wheel - "CVE-2025-59465" # Node only used for Admin UI build/prisma - "CVE-2025-55131" # Node only used for Admin UI build/prisma - "CVE-2025-59466" # Node only used for Admin UI build/prisma - "CVE-2025-55130" # Node only used for Admin UI build/prisma - "CVE-2025-59467" # Node only used for Admin UI build/prisma - "CVE-2026-21637" # Node only used for Admin UI build/prisma - "CVE-2025-55132" # Node only used for Admin UI build/prisma - "GHSA-hx9q-6w63-j58v" # orjson dumps recursion; allowlisted - "CVE-2025-15281" # No fix available yet - "CVE-2026-0865" # No fix available yet - "CVE-2025-15282" # No fix available yet - "CVE-2026-0672" # No fix available yet - "CVE-2025-15366" # No fix available yet - "CVE-2025-15367" # No fix available yet - "CVE-2025-12781" # No fix available yet - "CVE-2025-11468" # No fix available yet - "CVE-2026-1299" # Python 3.13 email module header injection - not applicable, LiteLLM doesn't use BytesGenerator for email serialization - "CVE-2026-0775" # npm cli incorrect permission assignment - no fix available yet, npm is only used at build/prisma-generate time - "GHSA-3ppc-4f35-3m26" # minimatch ReDoS via repeated wildcards - from nodejs_wheel bundled npm, not used in application runtime code - "GHSA-83g3-92jg-28cx" # tar arbitrary file read/write via hardlink - from nodejs_wheel bundled npm, not used in application runtime code - "CVE-2026-25639" # axios DoS via __proto__ in mergeConfig - transitive dev dep via @neondatabase/api-client, not imported in application code - "CVE-2026-2297" # Python 3.13 SourcelessFileLoader audit hook bypass - no fix available in base image - "GHSA-qffp-2rhf-9h96" # tar hardlink path traversal - from nodejs_wheel bundled npm, not used in application runtime code - "CVE-2026-2673" # OpenSSL 3.6.1 TLS 1.3 key exchange group negotiation issue - no fix available yet - "CVE-2026-3644" # Python 3.13 vulnerability - no fix available in base image - "CVE-2026-4224" # Python 3.13 Expat parser stack overflow in ElementDeclHandler - no fix available in base image - ) - - # Build JSON array of allowlisted CVE IDs for jq - ALLOWED_IDS_JSON=$(printf '%s\n' "${ALLOWED_CVES[@]}" | jq -R . | jq -s .) - - echo "Checking for vulnerabilities with CVSS score >= 4.0..." - echo "Allowlisted CVEs (ignored in threshold): ${ALLOWED_CVES[*]}" - echo "" - - # Show all high-severity vulnerabilities for transparency - TOTAL_HIGH_SEVERITY=$(grype litellm:latest -o json | jq -r ' - .matches[] - | select(.vulnerability.cvss[]?.metrics.baseScore >= 4.0) - | .vulnerability.id' | wc -l) - - if [ "$TOTAL_HIGH_SEVERITY" -gt 0 ]; then - echo "Total vulnerabilities found with CVSS >= 4.0: $TOTAL_HIGH_SEVERITY" - echo "" - echo "All high-severity vulnerabilities (including allowlisted):" - grype litellm:latest -o json | jq --argjson allow "$ALLOWED_IDS_JSON" -r ' - ["Package", "Version", "Vulnerability ID", "CVSS Score", "Allowlisted"], - (.matches[] - | select(.vulnerability.cvss[]?.metrics.baseScore >= 4.0) - | [.artifact.name, .artifact.version, .vulnerability.id, .vulnerability.cvss[0].metrics.baseScore, (if (.vulnerability.id as $id | $allow | index($id)) then "YES" else "NO" end)]) - | @tsv' | column -t -s $'\t' - echo "" - fi - - HIGH_SEVERITY_COUNT=$(grype litellm:latest -o json | jq --argjson allow "$ALLOWED_IDS_JSON" -r ' - .matches[] - | select(.vulnerability.cvss[]?.metrics.baseScore >= 4.0) - | select((.vulnerability.id as $id | $allow | index($id) | not)) - | .vulnerability.id' | wc -l) - - if [ "$HIGH_SEVERITY_COUNT" -gt 0 ]; then - echo "" - echo "==========================================" - echo "ERROR: Security Scan Failed" - echo "==========================================" - echo "Found $HIGH_SEVERITY_COUNT non-allowlisted vulnerabilities with CVSS score >= 4.0 in litellm:latest" - echo "" - echo "These vulnerabilities are NOT in the allowlist and must be addressed." - echo "Current allowlisted CVEs: ${ALLOWED_CVES[*]}" - echo "" - echo "Detailed vulnerability report:" - echo "" - grype litellm:latest -o json | jq --argjson allow "$ALLOWED_IDS_JSON" -r ' - ["Package", "Version", "Vulnerability ID", "CVSS Score", "Severity", "Fix Version", "Description"], - (.matches[] - | select(.vulnerability.cvss[]?.metrics.baseScore >= 4.0) - | select((.vulnerability.id as $id | $allow | index($id) | not)) - | [.artifact.name, .artifact.version, .vulnerability.id, .vulnerability.cvss[0].metrics.baseScore, .vulnerability.severity, (.vulnerability.fix.versions[0] // "No fix available"), .vulnerability.description]) - | @tsv' | column -t -s $'\t' - echo "" - echo "==========================================" - echo "Action Required:" - echo "==========================================" - echo "1. If a fix is available, update the package to the fixed version" - echo "2. If the vulnerability is not applicable or has no fix:" - echo " - Add the CVE/GHSA ID to ALLOWED_CVES array in ci_cd/security_scans.sh" - echo " - Add a comment explaining why it's safe to ignore" - echo "" - echo "Note: Some vulnerabilities may have multiple IDs (CVE-XXXX and GHSA-XXXX)." - echo "Add all relevant IDs to the allowlist if they refer to the same issue." - echo "==========================================" - echo "" - exit 1 - else - echo "No high-severity vulnerabilities (CVSS >= 4.0) found in litellm:latest" - fi - - echo "Grype scans completed successfully" -} - -# Main execution -main() { - echo "Installing security scanning tools..." - install_trivy - install_grype - - # echo "Running secret detection scans..." - # run_secret_detection - - echo "Running filesystem vulnerability scans..." - run_trivy_scans - - echo "Running Docker image vulnerability scans..." - run_grype_scans - - echo "All security scans completed successfully!" -} - -# Execute main function -main "$@" diff --git a/docs/my-website/.trivyignore b/docs/my-website/.trivyignore deleted file mode 100644 index 977504f2670..00000000000 --- a/docs/my-website/.trivyignore +++ /dev/null @@ -1,7 +0,0 @@ -# js-yaml CVE-2025-64718 -# This vulnerability is not applicable because we've forced js-yaml to version 4.1.1 -# via npm overrides in package.json. Trivy incorrectly reports this based on -# dependency requirements in the lockfile, but the actual installed version is 4.1.1. -# Verified with: npm list js-yaml -CVE-2025-64718 - diff --git a/scripts/install.sh b/scripts/install.sh index b9912287b70..03ae31cd18b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -83,8 +83,8 @@ echo "" header "Installing litellm[proxy]…" echo "" -"$PYTHON_BIN" -m pip install --upgrade "${LITELLM_PACKAGE}" \ - || die "pip install failed. Try manually: $PYTHON_BIN -m pip install '${LITELLM_PACKAGE}'" +"$PYTHON_BIN" -m pip install --only-binary :all: --upgrade "${LITELLM_PACKAGE}" \ + || die "pip install failed. Try manually: $PYTHON_BIN -m pip install --only-binary :all: '${LITELLM_PACKAGE}'" # ── find the litellm binary installed by pip for this Python ─────────────── # sysconfig.get_path('scripts') is where pip puts console scripts — reliable diff --git a/ui/litellm-dashboard/.trivyignore b/ui/litellm-dashboard/.trivyignore deleted file mode 100644 index 977504f2670..00000000000 --- a/ui/litellm-dashboard/.trivyignore +++ /dev/null @@ -1,7 +0,0 @@ -# js-yaml CVE-2025-64718 -# This vulnerability is not applicable because we've forced js-yaml to version 4.1.1 -# via npm overrides in package.json. Trivy incorrectly reports this based on -# dependency requirements in the lockfile, but the actual installed version is 4.1.1. -# Verified with: npm list js-yaml -CVE-2025-64718 -