fix(proxy): support wildcard patterns in JWT role_permissions.models - #27601
fix(proxy): support wildcard patterns in JWT role_permissions.models#27601Jwrede wants to merge 3 commits into
Conversation
can_rbac_role_call_model used a plain list membership check, so wildcard patterns like "bedrock-claude-*" or "*" in role_permissions models config were treated as literal strings and never matched concrete model names. Use fnmatch for pattern matching, consistent with how wildcards work in team/key model gating. Fixes BerriAI#27536
|
@greptileai review |
Greptile SummaryThis PR fixes wildcard pattern matching in JWT RBAC role model gating by replacing the plain Python
Confidence Score: 4/5Safe to merge; the fix is isolated, well-tested, and uses an already-imported module with no new dependencies or behavior changes outside the targeted method. The logic change is correct and the new tests cover the key cases. The only open item is that
|
| Filename | Overview |
|---|---|
| litellm/proxy/auth/handle_jwt.py | Replaces plain in membership check with fnmatch-aware pattern matching in can_rbac_role_call_model; fnmatch was already imported. The adjacent check_scope_based_access method has a parallel gap with the same plain in check. |
| tests/proxy_unit_tests/test_user_api_key_auth.py | Adds test_can_rbac_role_call_model_wildcard covering prefix wildcard, global wildcard, and non-matching case; existing tests are unchanged and not weakened. |
Comments Outside Diff (1)
-
litellm/proxy/auth/handle_jwt.py, line 910 (link)Parallel wildcard gap in
check_scope_based_accessThe adjacent
check_scope_based_accessmethod still uses a plainnot inmembership test onallowed_models(line 910), so scope-based model lists suffer the same wildcard-blindness that this PR just fixed for RBAC role permissions. A scope entry likebedrock-claude-*would still block all real model names. Worth applying the samefnmatchtreatment here for consistency.
Reviews (1): Last reviewed commit: "fix(proxy): support wildcard patterns in..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Move wildcard pattern tests into tests/test_litellm/ so they are included in Codecov coverage measurement.
| detail=f"Role={rbac_role} not allowed to call model={model}. Allowed models={role_based_models}", | ||
| ) | ||
| if model in role_based_models or any( | ||
| fnmatch.fnmatch(model, pattern) for pattern in role_based_models |
There was a problem hiding this comment.
Medium: Model allowlist expands fnmatch metacharacters
fnmatch treats ? and character classes like [eu] as wildcards, even when a role_permissions.models entry was intended to be an exact model alias. A user whose role is allowed to call a custom alias like prod-[eu] can now call prod-e or prod-u because this authz check interprets the alias as a pattern.
| fnmatch.fnmatch(model, pattern) for pattern in role_based_models | |
| re.fullmatch(re.escape(pattern).replace(r"\*", ".*"), model) is not None for pattern in role_based_models if "*" in pattern |
There was a problem hiding this comment.
Good catch -- fixed in bcc3472. Wildcard matching now only applies when the pattern contains *. Entries with ? or [...] are treated as exact model names via the model in role_based_models check. This matches the guard pattern used in guardrail_hooks. Added a test verifying that prod-[eu] rejects prod-e and model-v2? rejects model-v2x.
JWT RBAC model wildcard supportThis PR adds Status: 1 open |
fnmatch treats ? and [...] as wildcards, so a model alias like prod-[eu] would unintentionally match prod-e. Only apply fnmatch when the pattern contains *, treating all other entries as exact names. This matches the guard pattern used in guardrail_hooks.
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Summary
Fixes #27536
JWTAuthManager.can_rbac_role_call_modelused a plain Pythoninmembership check againstrole_permissions[].models, so wildcard patterns likebedrock-claude-*or*were treated as literal strings and never matched concrete model names. This caused 403 errors for users whose JWT role allowed wildcarded model access.The fix adds
fnmatchpattern matching (already imported in the file) alongside the exact-match check, sobedrock-claude-*matchesbedrock-claude-draft-rep-sonnetand*matches any model name -- consistent with how wildcards work in team and key model gating elsewhere in the proxy.Test plan
test_can_rbac_role_call_model-- existing exact-match tests still passtest_can_rbac_role_call_model_no_role_permissions-- existing no-permissions test still passestest_can_rbac_role_call_model_wildcard-- new test verifyingbedrock-claude-*matches,*matches all, and non-matching patterns still raise 403