Skip to content

[Fix] Backport /key/regenerate ownership-rebind + premium-gate guards (#27793) - #27819

Merged
yuneng-berri merged 1 commit into
litellm_1.84.0rc2from
litellm_backport_regenerate_guard_84rc2
May 13, 2026
Merged

[Fix] Backport /key/regenerate ownership-rebind + premium-gate guards (#27793)#27819
yuneng-berri merged 1 commit into
litellm_1.84.0rc2from
litellm_backport_regenerate_guard_84rc2

Conversation

@yuneng-berri

Copy link
Copy Markdown
Collaborator

Relevant issues

Backport of #27793 onto litellm_1.84.0rc2.

Summary

Failure Path (Before Fix)

A non-admin caller could rebind their own key's user_id via /key/regenerate. _execute_virtual_key_regeneration had org/team guards but no user_id guard, and prepare_key_update_data did not strip the field — it survived model_dump(exclude_unset=True) into the Prisma update. On the next request, _return_user_api_key_auth_obj resolved the rebound user_id against litellm_usertable and returned PROXY_ADMIN whenever the target row's user_role was admin.

Separately, the premium gate that allowed the master-key rotation branch to skip the enterprise check was a field-presence test, not an identity check — a non-premium caller could send any value in new_master_key and the premium check would no-op.

Fix

  • Extract /key/update's inline guard into a shared helper _validate_caller_can_change_key_ownership and call it from both /key/update and _execute_virtual_key_regeneration. Future regenerate-style endpoints inherit the guard for free.
  • Treat explicit-null and empty-string user_id as removal attempts, both 403-rejected for non-admin callers. Use data.model_fields_set to distinguish omitted from explicitly-set.
  • Verify the caller actually holds the master key via _is_master_key before allowing the non-premium master-key rotation path.

Changes

This is a clean backport of all three commits from #27793 onto the 1.84.0rc2 release branch. Source-file diff (+69/-18) and test-file diff (+154) match the original PR exactly. No code changes from the original PR.

Testing

  • pytest tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py -k "regenerate_user_id_rebind or regenerate_premium" -v — 6/6 pass on this branch.
  • pytest -k "key_regenerate or key_update or validate" — 45/45 related tests pass; no regressions in adjacent guards.

Type

🐛 Bug Fix
✅ Test

…e guards (#27793)

Backport of #27793 onto litellm_1.84.0rc2.

A non-admin caller could rebind their own key's user_id via /key/regenerate.
_execute_virtual_key_regeneration had org/team guards but no user_id guard,
and prepare_key_update_data did not strip the field — it survived
model_dump(exclude_unset=True) into the Prisma update. On the next request,
_return_user_api_key_auth_obj resolved the rebound user_id against
litellm_usertable and returned PROXY_ADMIN whenever the target row's
user_role was admin.

/key/update had the equivalent guard inline at _validate_update_key_data;
extract it to a shared helper _validate_caller_can_change_key_ownership and
call from both /key/update and _execute_virtual_key_regeneration.

Also tighten the premium gate that allowed the master-key rotation branch to
skip the enterprise check. The previous predicate was a field-presence test,
not an identity check. Verify the caller actually holds the master key via
_is_master_key before allowing the non-premium path.

Block explicit-null user_id and empty-string user_id as removal attempts;
both 403-reject for non-admin callers.
@greptile-apps

greptile-apps Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This backport closes two privilege-escalation paths in the key management layer: a non-admin user_id rebind via /key/regenerate, and a premium-gate bypass triggered by the mere presence of a new_master_key body field. It extracts an ownership-rebind guard into a shared helper and tightens the master-key identity check.

  • _validate_caller_can_change_key_ownership — new shared helper that uses model_fields_set to distinguish omitted vs. explicitly-set user_id, blocking null/empty-string removal and cross-user rebinds for non-admin callers; called from both /key/update and _execute_virtual_key_regeneration.
  • Premium gate fixis_master_key_regeneration now requires _is_master_key() in addition to a non-null new_master_key field, so only the actual master-key holder can skip the enterprise check.
  • 6 new unit tests covering the rebind guard (cross-user, empty-string, explicit-null, no-op) and the premium gate; no existing tests are modified.

Confidence Score: 4/5

The change is a targeted security backport with well-scoped tests; the two fixed attack paths are now properly gated and no existing test assertions are altered.

Both fixes are logically sound: the ownership guard correctly leverages model_fields_set to catch explicit-null user_id, and the premium gate now verifies actual master-key identity. The six new tests cover all critical cases. The patched security paths touch auth-critical code, so an extra reviewer pass is worthwhile before merging to a release branch.

The auth logic in key_management_endpoints.py — specifically the new helper and the premium gate block — deserves a careful read before merging to the release branch.

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/key_management_endpoints.py Adds _validate_caller_can_change_key_ownership helper and wires it into both /key/update and _execute_virtual_key_regeneration; tightens the premium-gate check to require actual master-key identity. Logic is correct and well-commented.
tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py Adds 6 new focused tests for the rebind guard and premium gate; no existing assertions are weakened or removed. All tests use mocks only — no real network calls.

Reviews (1): Last reviewed commit: "chore(proxy): backport /key/regenerate o..." | Re-trigger Greptile

@yuneng-berri
yuneng-berri merged commit 2b189be into litellm_1.84.0rc2 May 13, 2026
105 of 113 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_backport_regenerate_guard_84rc2 branch May 13, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant