From e7714f0ce6115d522d7ca658ded4b4a5058a153c Mon Sep 17 00:00:00 2001 From: Krish Dholakia Date: Sat, 7 Mar 2026 18:31:27 -0800 Subject: [PATCH] Fix CVEs: bump tar/minimatch/pypdf + harden Docker SBOM patching (#23082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(docker): bump tar/minimatch/pypdf for CVE fixes + harden SBOM patching - Bump tar 7.5.8→7.5.10, minimatch 10.2.1→10.2.4, pypdf 6.6.2→6.7.3 - Add sed-based SBOM metadata patching with properly indented find/sed - Add npm package manager cleanup (apk del / apt-get purge) to remove stale SBOM entries from image scanners - Scope || true to only apk del via brace grouping { ... || true; } - Guard npm root -g with non-empty assertion to prevent silent failures - Scope minimatch sed regex to ^10.x to avoid matching other major versions Addresses: CVE-2026-27903, CVE-2026-27904, GHSA-qffp-2rhf-9h96, CVE-2026-27888 Co-Authored-By: Claude Opus 4.6 * fix(docker): scope find to /usr/local/lib /usr/lib, drop autoremove - Replace `find /` with `find /usr/local/lib /usr/lib` to avoid traversing /proc, /sys, /dev during SBOM metadata patching - Remove `apt-get autoremove -y` from Debian-based Dockerfiles to prevent nodejs from being removed as an auto-installed dependency Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- Dockerfile | 13 +++++++++++-- docker/Dockerfile.custom_ui | 7 +++++-- docker/Dockerfile.database | 8 ++++++-- docker/Dockerfile.dev | 8 ++++++-- docker/Dockerfile.non_root | 8 ++++++-- docs/my-website/package.json | 2 +- litellm-js/spend-logs/package.json | 4 ++-- package.json | 4 ++-- requirements.txt | 2 +- tests/proxy_admin_ui_tests/package.json | 4 ++-- .../proxy_admin_ui_tests/ui_unit_tests/package.json | 4 ++-- ui/litellm-dashboard/package.json | 4 ++-- 12 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 605e702d2a..75ccff2966 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ USER root # Install runtime dependencies (libsndfile needed for audio processing on ARM64) RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile && \ - npm install -g npm@latest tar@7.5.8 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ + npm install -g npm@latest tar@7.5.10 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ # SECURITY FIX: npm bundles tar, glob, and brace-expansion at multiple nested # levels inside its dependency tree. `npm install -g ` only creates a # SEPARATE global package, it does NOT replace npm's internal copies. @@ -70,7 +70,15 @@ RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile find "$GLOBAL/npm" -type d -name "diff" -path "*/node_modules/diff" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/diff" "$d"; \ done && \ - npm cache clean --force + # SECURITY FIX: patch npm's own package.json metadata so scanners see the + # actual installed versions instead of the stale declared dependencies. + find /usr/local/lib /usr/lib -path "*/node_modules/npm/package.json" -exec \ + sed -i 's/"tar": "\^7\.5\.[0-9]*"/"tar": "^7.5.10"/g; s/"minimatch": "\^10\.[0-9.]*"/"minimatch": "^10.2.4"/g' {} + 2>/dev/null && \ + npm cache clean --force && \ + # Remove the apk-tracked npm so its stale SBOM metadata (tar 7.5.9) is + # no longer visible to image scanners. The globally installed npm@latest + # at /usr/local/lib/node_modules/npm/ remains fully functional. + { apk del --no-cache npm 2>/dev/null || true; } WORKDIR /app # Copy the current directory contents into the container at /app @@ -96,6 +104,7 @@ RUN find /usr/lib -type f -path "*/tornado/test/*" -delete && \ # npm with old vulnerable deps at /usr/lib/python3.*/site-packages/nodejs_wheel/. # Patch every copy of tar, glob, and brace-expansion inside that tree. RUN GLOBAL="$(npm root -g)" && \ + [ -n "$GLOBAL" ] || { echo "ERROR: npm root -g returned empty; aborting"; exit 1; } && \ find /usr/lib -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ done && \ diff --git a/docker/Dockerfile.custom_ui b/docker/Dockerfile.custom_ui index fb98846a6c..4052c7a51b 100644 --- a/docker/Dockerfile.custom_ui +++ b/docker/Dockerfile.custom_ui @@ -19,7 +19,7 @@ RUN apt-get update && apt-get upgrade -y \ libgnutls30 \ libc6 && \ apt-get install -y nodejs npm && \ - npm install -g npm@latest tar@7.5.8 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.1 diff@8.0.3 && \ + npm install -g npm@latest tar@7.5.10 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ GLOBAL="$(npm root -g)" && \ find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ @@ -36,7 +36,10 @@ RUN apt-get update && apt-get upgrade -y \ find "$GLOBAL/npm" -type d -name "diff" -path "*/node_modules/diff" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/diff" "$d"; \ done && \ - npm cache clean --force + find /usr/local/lib /usr/lib -path "*/node_modules/npm/package.json" -exec \ + sed -i 's/"tar": "\^7\.5\.[0-9]*"/"tar": "^7.5.10"/g; s/"minimatch": "\^10\.[0-9.]*"/"minimatch": "^10.2.4"/g' {} + 2>/dev/null && \ + npm cache clean --force && \ + apt-get purge -y npm # Copy the UI source into the container COPY ./ui/litellm-dashboard /app/ui/litellm-dashboard diff --git a/docker/Dockerfile.database b/docker/Dockerfile.database index 371766bd9d..962d129e57 100644 --- a/docker/Dockerfile.database +++ b/docker/Dockerfile.database @@ -50,7 +50,7 @@ USER root # Install runtime dependencies RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile && \ - npm install -g npm@latest tar@7.5.8 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.1 diff@8.0.3 && \ + npm install -g npm@latest tar@7.5.10 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 && \ GLOBAL="$(npm root -g)" && \ find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ @@ -67,7 +67,10 @@ RUN apk add --no-cache bash openssl tzdata nodejs npm python3 py3-pip libsndfile find "$GLOBAL/npm" -type d -name "diff" -path "*/node_modules/diff" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/diff" "$d"; \ done && \ - npm cache clean --force + find /usr/local/lib /usr/lib -path "*/node_modules/npm/package.json" -exec \ + sed -i 's/"tar": "\^7\.5\.[0-9]*"/"tar": "^7.5.10"/g; s/"minimatch": "\^10\.[0-9.]*"/"minimatch": "^10.2.4"/g' {} + 2>/dev/null && \ + npm cache clean --force && \ + { apk del --no-cache npm 2>/dev/null || true; } WORKDIR /app # Copy the current directory contents into the container at /app @@ -85,6 +88,7 @@ RUN pip install *.whl /wheels/* --no-index --find-links=/wheels/ && rm -f *.whl # npm with old vulnerable deps at /usr/lib/python3.*/site-packages/nodejs_wheel/. # Patch every copy of tar, glob, and brace-expansion inside that tree. RUN GLOBAL="$(npm root -g)" && \ + [ -n "$GLOBAL" ] || { echo "ERROR: npm root -g returned empty; aborting"; exit 1; } && \ find /usr/lib -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ done && \ diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index a5312dec9e..cfc4c646ba 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -75,7 +75,7 @@ RUN apt-get update && apt-get upgrade -y \ nodejs \ npm \ && rm -rf /var/lib/apt/lists/* \ - && npm install -g npm@latest tar@7.5.8 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.1 diff@8.0.3 \ + && npm install -g npm@latest tar@7.5.10 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ && GLOBAL="$(npm root -g)" \ && find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ @@ -92,7 +92,10 @@ RUN apt-get update && apt-get upgrade -y \ && find "$GLOBAL/npm" -type d -name "diff" -path "*/node_modules/diff" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/diff" "$d"; \ done \ - && npm cache clean --force + && find /usr/local/lib /usr/lib -path "*/node_modules/npm/package.json" -exec \ + sed -i 's/"tar": "\^7\.5\.[0-9]*"/"tar": "^7.5.10"/g; s/"minimatch": "\^10\.[0-9.]*"/"minimatch": "^10.2.4"/g' {} + 2>/dev/null \ + && npm cache clean --force \ + && apt-get purge -y npm WORKDIR /app @@ -114,6 +117,7 @@ RUN pip install --no-cache-dir *.whl /wheels/* --no-index --find-links=/wheels/ # npm with old vulnerable deps at /usr/lib/python3.*/site-packages/nodejs_wheel/. # Patch every copy of tar, glob, and brace-expansion inside that tree. RUN GLOBAL="$(npm root -g)" && \ + [ -n "$GLOBAL" ] || { echo "ERROR: npm root -g returned empty; aborting"; exit 1; } && \ find /usr/lib -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ done && \ diff --git a/docker/Dockerfile.non_root b/docker/Dockerfile.non_root index fda591df08..fbc16e4f87 100644 --- a/docker/Dockerfile.non_root +++ b/docker/Dockerfile.non_root @@ -106,7 +106,7 @@ RUN for i in 1 2 3; do \ apk add --no-cache python3 py3-pip bash openssl tzdata nodejs npm supervisor && break || sleep 5; \ done \ && apk upgrade --no-cache nodejs \ - && npm install -g npm@latest tar@7.5.8 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.1 diff@8.0.3 \ + && npm install -g npm@latest tar@7.5.10 glob@11.1.0 @isaacs/brace-expansion@5.0.1 minimatch@10.2.4 diff@8.0.3 \ && GLOBAL="$(npm root -g)" \ && find "$GLOBAL/npm" -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ @@ -123,7 +123,10 @@ RUN for i in 1 2 3; do \ && find "$GLOBAL/npm" -type d -name "diff" -path "*/node_modules/diff" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/diff" "$d"; \ done \ - && npm cache clean --force + && find /usr/local/lib /usr/lib -path "*/node_modules/npm/package.json" -exec \ + sed -i 's/"tar": "\^7\.5\.[0-9]*"/"tar": "^7.5.10"/g; s/"minimatch": "\^10\.[0-9.]*"/"minimatch": "^10.2.4"/g' {} + 2>/dev/null \ + && npm cache clean --force \ + && { apk del --no-cache npm 2>/dev/null || true; } # Copy artifacts from builder COPY --from=builder /app/requirements.txt /app/requirements.txt @@ -169,6 +172,7 @@ RUN pip install --no-index --find-links=/wheels/ -r requirements.txt && \ # npm with old vulnerable deps at /usr/lib/python3.*/site-packages/nodejs_wheel/. # Patch every copy of tar, glob, and brace-expansion inside that tree. RUN GLOBAL="$(npm root -g)" && \ + [ -n "$GLOBAL" ] || { echo "ERROR: npm root -g returned empty; aborting"; exit 1; } && \ find /usr/lib -type d -name "tar" -path "*/node_modules/tar" | while read d; do \ rm -rf "$d" && cp -rL "$GLOBAL/tar" "$d"; \ done && \ diff --git a/docs/my-website/package.json b/docs/my-website/package.json index 758e53ebf5..20462de2dd 100644 --- a/docs/my-website/package.json +++ b/docs/my-website/package.json @@ -61,7 +61,7 @@ "mermaid": ">=11.10.0", "gray-matter": "4.0.3", "glob": ">=11.1.0", - "tar": ">=7.5.8", + "tar": ">=7.5.10", "minimatch": ">=10.2.4", "diff": ">=8.0.3", "@isaacs/brace-expansion": ">=5.0.1", diff --git a/litellm-js/spend-logs/package.json b/litellm-js/spend-logs/package.json index 5a7a08cb9e..adfe49017d 100644 --- a/litellm-js/spend-logs/package.json +++ b/litellm-js/spend-logs/package.json @@ -12,8 +12,8 @@ }, "overrides": { "glob": ">=11.1.0", - "tar": ">=7.5.8", - "minimatch": ">=10.2.1", + "tar": ">=7.5.10", + "minimatch": ">=10.2.4", "diff": ">=8.0.3", "@isaacs/brace-expansion": ">=5.0.1", "@babel/traverse": ">=7.23.2", diff --git a/package.json b/package.json index a45e116b27..b5be819a45 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ }, "overrides": { "glob": ">=11.1.0", - "tar": ">=7.5.8", - "minimatch": ">=10.2.1", + "tar": ">=7.5.10", + "minimatch": ">=10.2.4", "diff": ">=8.0.3", "@isaacs/brace-expansion": ">=5.0.1", "@babel/traverse": ">=7.23.2", diff --git a/requirements.txt b/requirements.txt index a6446dc0cf..103b298145 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ jsonschema>=4.23.0,<5.0.0 # validating json schema - aligned with openapi-core + websockets==15.0.1 # for realtime API soundfile==0.12.1 # for audio file processing openapi-core==0.21.0 # for OpenAPI compliance tests -pypdf>=6.6.2 # for PDF text extraction in RAG ingestion +pypdf>=6.7.3 # for PDF text extraction in RAG ingestion (CVE-2026-27888) ######################## # LITELLM ENTERPRISE DEPENDENCIES diff --git a/tests/proxy_admin_ui_tests/package.json b/tests/proxy_admin_ui_tests/package.json index 037ec7082a..ac726b64b7 100644 --- a/tests/proxy_admin_ui_tests/package.json +++ b/tests/proxy_admin_ui_tests/package.json @@ -13,8 +13,8 @@ }, "overrides": { "glob": ">=11.1.0", - "tar": ">=7.5.8", - "minimatch": ">=10.2.1", + "tar": ">=7.5.10", + "minimatch": ">=10.2.4", "diff": ">=8.0.3", "@isaacs/brace-expansion": ">=5.0.1", "@babel/traverse": ">=7.23.2", diff --git a/tests/proxy_admin_ui_tests/ui_unit_tests/package.json b/tests/proxy_admin_ui_tests/ui_unit_tests/package.json index eb9c7473a5..9f1c689721 100644 --- a/tests/proxy_admin_ui_tests/ui_unit_tests/package.json +++ b/tests/proxy_admin_ui_tests/ui_unit_tests/package.json @@ -25,8 +25,8 @@ }, "overrides": { "glob": ">=11.1.0", - "tar": ">=7.5.8", - "minimatch": ">=10.2.1", + "tar": ">=7.5.10", + "minimatch": ">=10.2.4", "diff": ">=8.0.3", "@isaacs/brace-expansion": ">=5.0.1", "@babel/traverse": ">=7.23.2", diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index ea84ea6f40..06aff85e3f 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -88,8 +88,8 @@ "mermaid": ">=11.10.0", "js-yaml": ">=4.1.1", "glob": ">=11.1.0", - "tar": ">=7.5.8", - "minimatch": ">=10.2.1", + "tar": ">=7.5.10", + "minimatch": ">=10.2.4", "@isaacs/brace-expansion": ">=5.0.1", "node-forge": ">=1.3.2", "lodash-es": ">=4.17.23",