bump: version 1.84.6 (backport CrowdStrike AIDR metadata capture + identity fix) - #29994
Conversation
Capture user_id and extra_info from metadata or litellm_metadata. The single-bag read dropped identity whenever a request carried a present litellm_metadata field (null or a user-supplied dict), since /chat/completions routes the authenticated identity into metadata while the guardrail read litellm_metadata first
Greptile SummaryThis PR backports CrowdStrike AIDR user/model identity capture to
Confidence Score: 3/5Safe to merge once the merge order in _merge_metadata_bags is corrected; as-is, caller-supplied litellm_metadata can overwrite the auth-system identity in the outbound CrowdStrike AIDR payload. The _merge_metadata_bags helper iterates metadata then litellm_metadata, so the second dict values win on key collision. Since litellm auth middleware writes verified caller identity into metadata, and litellm_metadata is partially shaped by the incoming request body, a caller who includes user_api_key_user_id or user_api_key_user_email in their litellm_metadata will silently replace the authenticated values in the CrowdStrike AIDR audit payload. None of the new regression tests exercise a conflict case, so the bug passes undetected. litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py - specifically the _merge_metadata_bags iteration order.
|
| Filename | Overview |
|---|---|
| litellm/proxy/guardrails/guardrail_hooks/crowdstrike_aidr/crowdstrike_aidr.py | Adds _merge_metadata_bags helper and metadata/identity fields in the AIDR payload; merge order gives litellm_metadata (partially caller-controlled) precedence over metadata (auth-system-set), which can allow identity spoofing in the CrowdStrike AIDR audit payload. |
| tests/test_litellm/proxy/guardrails/guardrail_hooks/test_crowdstrike_aidr.py | Adds three new feature tests and a four-parametrized regression test; strengthens two existing config-failure tests with monkeypatch.delenv to prevent false-passes when env vars happen to be set. No real network calls - all HTTP interactions are mocked. |
| pyproject.toml | Version bump from 1.84.5 to 1.84.6 in both [project] and [tool.commitizen] sections. |
Reviews (1): Last reviewed commit: "bump: version 1.84.5 → 1.84.6" | Re-trigger Greptile
| def _merge_metadata_bags(request_data: Mapping[str, Any]) -> Optional[dict[str, Any]]: | ||
| merged: dict[str, Any] = {} | ||
| present = False | ||
| for bag in (request_data.get("metadata"), request_data.get("litellm_metadata")): |
There was a problem hiding this comment.
Merge order lets caller-supplied data overwrite authenticated identity
metadata is applied first, then litellm_metadata overwrites any shared keys. Because litellm's auth middleware writes the authenticated caller identity (user_api_key_user_id, user_api_key_user_email) into metadata, a caller who deliberately (or accidentally) includes these same keys in their request-body litellm_metadata will silently replace the system-verified identity in the outbound CrowdStrike AIDR payload. Reversing the iteration order ensures the system-set metadata values always win on conflict.
| for bag in (request_data.get("metadata"), request_data.get("litellm_metadata")): | |
| for bag in (request_data.get("litellm_metadata"), request_data.get("metadata")): |
Relevant issues
Backports the CrowdStrike AIDR user/model metadata capture (#29517, authored by Kenan Yildirim) plus the follow-up metadata-bag fix to
stable/1.84.x, and bumps the patch version to 1.84.6 for a release.The fix corrects a bug in #29517: it resolved the request metadata from a single bag with
request_data.get("litellm_metadata", request_data.get("metadata")). Becausedict.getreturns the stored value when the key is present, a presentlitellm_metadata(an explicitnull, or a caller-supplied dict) shadowedmetadata, where/chat/completionsplaces the authenticated identity. Souser_idandextra_info.user_namewere silently dropped from the outbound guard payload for any request that carried alitellm_metadatafield. The fix reads identity from both bags.Adaptation note (not a clean cherry-pick)
stable/1.84.xcarries an older CrowdStrike implementation than #29517 was written against, so the cherry-pick required three deliberate adaptations, each preserved here:guard_inputis a plaindicton this branch, so the payload keeps"guard_input": guard_inputrather thanguard_input.model_dump(mode="json")(the latter wouldAttributeErroron a dict). Kenan'sdict[str, Any]annotation is kept.from collections.abc import Mapping, which this branch did not import but the metadata code needs.test_apply_guardrail_request_skipped_messages_stay_aligned) from a different change that is not on this branch; only Kenan's three new tests were taken.Kenan's authorship is preserved on his commit.
Pre-Submission checklist
Screenshots / Proof of Fix
Full CrowdStrike guardrail suite on this branch (stable's 9 tests + Kenan's 3 + the regression test's 4 parametrizations):
The regression test
test_apply_guardrail_reads_identity_from_either_metadata_bagfails on the pre-fix single-bag read (3 of 4 parametrizations dropuser_id) and passes after. Black, Ruff, and MyPy pass on the changed module, anduv lock --checkis consistent with the 1.84.6 bump.Type
🐛 Bug Fix
Changes
Three commits on top of
stable/1.84.x: Kenan's #29517 feature (adapted to this branch as above), the metadata-bag fix with a_merge_metadata_bagshelper plus a parametrized regression test, and the 1.84.5 -> 1.84.6 version bump inpyproject.tomlanduv.lock.