diff --git a/.trivyignore b/.trivyignore index 0d04ecacdb5..d11d4ece90d 100644 --- a/.trivyignore +++ b/.trivyignore @@ -10,3 +10,11 @@ GHSA-h25m-26qc-wcjf # MEDIUM: Image Optimizer DoS CVE-2025-59471 + +# DOMPurify XSS (transitive dep of @docusaurus/theme-mermaid) +# Fix: override dompurify>=3.3.2 in docs/my-website/package.json +CVE-2026-0540 + +# SVGO Billion Laughs DoS (transitive dep of @docusaurus/core) +# Fix: override svgo>=3.3.3 in docs/my-website/package.json +CVE-2026-29074 diff --git a/docs/my-website/package.json b/docs/my-website/package.json index acdd7463a36..44f25a97d96 100644 --- a/docs/my-website/package.json +++ b/docs/my-website/package.json @@ -53,7 +53,9 @@ "form-data": ">=4.0.4", "mermaid": ">=11.10.0", "gray-matter": "4.0.3", - "node-forge": ">=1.3.2" + "node-forge": ">=1.3.2", + "dompurify": ">=3.3.2", + "svgo": ">=3.3.3" }, "overrides": { "webpack-dev-server": ">=5.2.1", @@ -93,6 +95,9 @@ "axios": ">=0.30.2", "webpack": ">=5.94.0", "serve-static": ">=1.16.0", - "path-to-regexp": ">=0.1.12" - } + "path-to-regexp": ">=0.1.12", + "dompurify": ">=3.3.2", + "svgo": ">=3.3.3" + }, + "resolutions_note": "dompurify and svgo overrides fix CVE-2026-0540 and CVE-2026-29074" } diff --git a/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py b/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py index 9dea744c4e8..fa9f4153c5a 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py +++ b/litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py @@ -5,7 +5,7 @@ from typing_extensions import Any, override from fastapi import HTTPException from litellm._logging import verbose_proxy_logger -from litellm.integrations.custom_guardrail import CustomGuardrail +from litellm.integrations.custom_guardrail import CustomGuardrail, log_guardrail_information from litellm.llms.custom_httpx.http_handler import ( get_async_httpx_client, httpxSpecialProvider, @@ -272,6 +272,7 @@ class CrowdStrikeAIDRHandler(CustomGuardrail): transformed_texts.append(texts[len(transformed_texts)]) return transformed_texts[: len(texts)] + @log_guardrail_information @override async def apply_guardrail( self, diff --git a/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py b/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py index 83f7bb520af..8c732e0596e 100644 --- a/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py +++ b/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py @@ -1157,10 +1157,10 @@ def test_create_file_with_deep_nested_litellm_metadata( ) # Verify success - assert response.status_code == 200 + assert response.status_code == 200, f"Expected 200, got {response.status_code}. Response: {response.text}" result = response.json() assert result["id"] == "file-test-456" - + # Verify deeply nested metadata was correctly parsed assert "config" in captured_litellm_metadata assert "database" in captured_litellm_metadata["config"] diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx index f6fcfb2fb74..462b0a3d99d 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx @@ -113,7 +113,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); const input = screen.getByTestId("duration-input"); - expect(input).toHaveAttribute("placeholder", "e.g., 30d or -1 to never expire"); + expect(input).toHaveAttribute("placeholder", "e.g., 30d"); }); it("should show correct tooltip in create mode", () => { @@ -121,12 +121,12 @@ describe("KeyLifecycleSettings", () => { const tooltips = screen.getAllByTestId("tooltip"); const expiryTooltip = tooltips.find((tooltip) => - tooltip.getAttribute("title")?.includes("Leave empty to never expire") + tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged") ); expect(expiryTooltip).toBeInTheDocument(); expect(expiryTooltip).toHaveAttribute( "title", - "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to never expire." + "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged." ); }); @@ -135,12 +135,12 @@ describe("KeyLifecycleSettings", () => { const tooltips = screen.getAllByTestId("tooltip"); const expiryTooltip = tooltips.find((tooltip) => - tooltip.getAttribute("title")?.includes("Use -1 to never expire") + tooltip.getAttribute("title")?.includes("Leave empty to keep the current expiry unchanged") ); expect(expiryTooltip).toBeInTheDocument(); expect(expiryTooltip).toHaveAttribute( "title", - "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Use -1 to never expire." + "Set when this key should expire. Format: 30s (seconds), 30m (minutes), 30h (hours), 30d (days). Leave empty to keep the current expiry unchanged." ); }); diff --git a/ui/litellm-dashboard/src/components/navbar.test.tsx b/ui/litellm-dashboard/src/components/navbar.test.tsx index 125187e2340..0eeeb547c54 100644 --- a/ui/litellm-dashboard/src/components/navbar.test.tsx +++ b/ui/litellm-dashboard/src/components/navbar.test.tsx @@ -6,6 +6,7 @@ import Navbar from "./navbar"; // Mock the hooks and utilities vi.mock("@/components/networking", () => ({ getProxyBaseUrl: vi.fn(() => "http://localhost:4000"), + serverRootPath: "/", })); vi.mock("@/utils/proxyUtils", () => ({