fix(security): hash Bearer-prefixed API keys in spend logs - #31799
Conversation
The safety-net hash in get_logging_payload only checked for keys starting with 'sk-', missing keys that arrived as 'Bearer sk-...'. This caused plaintext API keys to be stored in SpendLogs for failed requests while successful requests correctly stored SHA256 hashes. Adds _hash_api_key_for_spend_log that strips the Bearer prefix before hashing, applied to both the api_key column and the metadata.user_api_key field in spend log payloads.
Greptile SummaryThis PR adds a new helper function
Confidence Score: 5/5Safe to merge — the change is isolated to spend-log serialization, adds no new I/O, and the tests directly exercise both the helper and the full payload path. The new helper correctly strips the Bearer prefix before hashing and is idempotent for already-hashed tokens. It is applied consistently in both the No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/proxy/spend_tracking/spend_tracking_utils.py | Adds _hash_api_key_for_spend_log that strips the Bearer prefix before hashing; applies it to both the api_key column and metadata.user_api_key JSON field. Logic is correct and idempotent for already-hashed tokens. |
| tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py | Adds TestHashApiKeyForSpendLog (6 unit tests) and one integration test for get_logging_payload; covers Bearer/bare/case-insensitive/already-hashed/non-sk variants and the full failure path. No real network calls; mock-only. |
Reviews (3): Last reviewed commit: "fix: strip Bearer prefix from non-sk key..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@greptileai review |
|
|
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 4e0117c. Configure here.
The spend-log helper no longer treats a 64-hex shape as proof a value was already hashed, so this case has to say where the hash came from. Reconciles the test that came in with BerriAI#31799 against that change.
Relevant issues
Resolves LIT-4121
Linear ticket
Resolves LIT-4121
Pre-Submission checklist
@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewScreenshots / Proof of Fix
To verify the fix, run the proxy and send a request with an invalid model that triggers a failure:
Then query
LiteLLM_SpendLogswherestatus = 'failure'; theapi_keycolumn should now contain a 64-char SHA256 hex digest instead ofBearer sk-...Type
Bug Fix
Changes
The safety-net hash in
get_logging_payloadonly checkedapi_key.startswith("sk-"), so keys arriving as"Bearer sk-..."on the failure path bypassed hashing and were stored in plaintext in both theapi_keycolumn and themetadata.user_api_keyJSON field ofLiteLLM_SpendLogsThe fix adds
_hash_api_key_for_spend_log(api_key) -> strwhich strips a case-insensitiveBearerprefix before checking forsk-and hashing viahash_token. The fallback path also returns the stripped token (without the Bearer prefix) for non-sk keys, so the prefix is never persisted. Applied in two places:get_logging_payload(theapi_keycolumn)_get_spend_logs_metadata(theuser_api_keyfield inside the JSON metadata column)Regression tests cover Bearer-prefixed, bare, case-insensitive, already-hashed, Bearer-prefixed non-sk keys, idempotency, and the full
get_logging_payloadintegration pathNote
High Risk
Security fix for credential leakage in LiteLLM_SpendLogs; scope is limited to spend-tracking serialization with added regression tests.
Overview
Fixes LIT-4121: failed-request spend logs could persist plaintext
Bearer sk-...because hashing only ran when the value started withsk-.Adds
_hash_api_key_for_spend_log, which strips a case-insensitiveBearerprefix, hashessk-tokens viahash_token, and leaves already-hashed values unchanged. It is used when building theapi_keycolumn inget_logging_payloadandmetadata.user_api_keyin_get_spend_logs_metadata.Regression tests cover Bearer/bare/case variants, non-
sktokens, and the full failureget_logging_payloadpath.Reviewed by Cursor Bugbot for commit 4e0117c. Bugbot is set up for automated code reviews on this repo. Configure here.