From 650dbf49b4fbf9181f0bdc6cbfa7612c2ca748ae Mon Sep 17 00:00:00 2001 From: kerry Date: Thu, 24 Sep 2026 04:05:18 +0000 Subject: [PATCH] fix(usage): reject non-finite spend and empty key in page cursors Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/management_endpoints/common_daily_activity.py | 6 +++++- .../management_endpoints/test_common_daily_activity.py | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/management_endpoints/common_daily_activity.py b/litellm/proxy/management_endpoints/common_daily_activity.py index dd62126e01f..26900a0e7aa 100644 --- a/litellm/proxy/management_endpoints/common_daily_activity.py +++ b/litellm/proxy/management_endpoints/common_daily_activity.py @@ -2,6 +2,7 @@ import asyncio import base64 import binascii import json +import math from collections.abc import Awaitable, Callable, Mapping, Sequence from collections.abc import Set as AbstractSet from dataclasses import dataclass @@ -840,9 +841,12 @@ def decode_key_page_cursor(raw: str) -> KeyPageCursor | None: except (ValueError, binascii.Error): return None try: - return _KEY_PAGE_CURSOR_ADAPTER.validate_json(decoded) + cursor: Final = _KEY_PAGE_CURSOR_ADAPTER.validate_json(decoded) except ValidationError: return None + if not math.isfinite(cursor.spend) or cursor.api_key == "": + return None + return cursor def _build_aggregated_sql_query( diff --git a/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py b/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py index 17b02ec02f2..2d03405f0e7 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py +++ b/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py @@ -2888,6 +2888,9 @@ class TestKeyPageCursorCodec: "aGVsbG8=", # valid base64, not json "eyJmb28iOiAxfQ==", # json object missing both fields "eyJzcGVuZCI6ICIxLjUiLCAiYXBpX2tleSI6IDd9", # wrong types + "eyJzcGVuZCI6IE5hTiwgImFwaV9rZXkiOiAiayJ9", # {"spend": NaN, "api_key": "k"} + "eyJzcGVuZCI6IEluZmluaXR5LCAiYXBpX2tleSI6ICJrIn0=", # {"spend": Infinity, "api_key": "k"} + "eyJzcGVuZCI6IDEuMCwgImFwaV9rZXkiOiAiIn0=", # {"spend": 1.0, "api_key": ""} ], ) def test_malformed_returns_none(self, raw):