Skip to content

fix(proxy): support wildcard patterns in JWT role_permissions.models - #27601

Closed
Jwrede wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
Jwrede:fix/jwt-rbac-wildcard-models
Closed

fix(proxy): support wildcard patterns in JWT role_permissions.models#27601
Jwrede wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
Jwrede:fix/jwt-rbac-wildcard-models

Conversation

@Jwrede

@Jwrede Jwrede commented May 10, 2026

Copy link
Copy Markdown

Summary

Fixes #27536

JWTAuthManager.can_rbac_role_call_model used a plain Python in membership check against role_permissions[].models, so wildcard patterns like bedrock-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 fnmatch pattern matching (already imported in the file) alongside the exact-match check, so bedrock-claude-* matches bedrock-claude-draft-rep-sonnet and * 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 pass
  • test_can_rbac_role_call_model_no_role_permissions -- existing no-permissions test still passes
  • test_can_rbac_role_call_model_wildcard -- new test verifying bedrock-claude-* matches, * matches all, and non-matching patterns still raise 403

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
@Jwrede

Jwrede commented May 10, 2026

Copy link
Copy Markdown
Author

@greptileai review

@greptile-apps

greptile-apps Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes wildcard pattern matching in JWT RBAC role model gating by replacing the plain Python in check in can_rbac_role_call_model with a combined exact-match + fnmatch.fnmatch check, so patterns like bedrock-claude-* or * correctly match concrete model names instead of raising 403 errors.

  • handle_jwt.py: The can_rbac_role_call_model method now allows access when the requested model matches any pattern in role_based_models via fnmatch, using the module already imported at the top of the file.
  • test_user_api_key_auth.py: A new test_can_rbac_role_call_model_wildcard test covers prefix wildcards, the global * wildcard, and non-matching patterns; existing tests are untouched.

Confidence Score: 4/5

Safe 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 check_scope_based_access in the same file has the same plain in check for scope-based model lists, which would still silently ignore wildcard patterns — a small but real inconsistency left behind.

litellm/proxy/auth/handle_jwt.py — the check_scope_based_access method at line 910 still uses a plain membership check that doesn't benefit from the wildcard fix applied here.

Important Files Changed

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)

  1. litellm/proxy/auth/handle_jwt.py, line 910 (link)

    P2 Parallel wildcard gap in check_scope_based_access

    The adjacent check_scope_based_access method still uses a plain not in membership test on allowed_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 like bedrock-claude-* would still block all real model names. Worth applying the same fnmatch treatment here for consistency.

Reviews (1): Last reviewed commit: "fix(proxy): support wildcard patterns in..." | Re-trigger Greptile

@codecov

codecov Bot commented May 10, 2026

Copy link
Copy Markdown

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.
Comment thread litellm/proxy/auth/handle_jwt.py Outdated
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@veria-ai

veria-ai Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

JWT RBAC model wildcard support

This PR adds * wildcard matching for role_permissions.models while preserving exact model-name allowlist checks. I reviewed the RBAC call path and the updated metacharacter tests; I did not find a new security issue in the changed surface.


Status: 1 open
Risk: 2/10

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.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

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.

@github-actions github-actions Bot added the stale label Aug 9, 2026
@github-actions github-actions Bot closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: role_permissions.models in JWT auth does not honor wildcards (e.g. bedrock-claude-*, *)

2 participants