Skip to content

fix(proxy): tighten role gating on /get/config/callbacks response - #31745

Merged
yucheng-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_veria_440_admin_viewer_secrets
Jul 2, 2026
Merged

fix(proxy): tighten role gating on /get/config/callbacks response#31745
yucheng-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_veria_440_admin_viewer_secrets

Conversation

@yucheng-berri

@yucheng-berri yucheng-berri commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Resolves LIT-4115

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Live-reproduced against a local proxy. Detailed repro steps + before/after payloads are on the internal Linear ticket (LIT-4115); omitted here to avoid publishing a concrete attack payload.

Summary of the behavior change:

  • Callers who are not full PROXY_ADMIN (e.g. PROXY_ADMIN_VIEW_ONLY) now receive "REDACTED" in place of sensitive values in the /get/config/callbacks response.
  • Non-sensitive routing fields (host / base URL / port style values) remain visible so the UI can label which integration is wired up.
  • Full PROXY_ADMIN sees everything unchanged so the edit form round-trips on save without the UI silently overwriting stored values with the literal string "REDACTED".
  • Same posture as PR fix: tighten role-based visibility of config and MCP fields #30587, which closed the equivalent leak on /config/field/info, /config/list, and MCP routes but did not touch this handler.

Type

🐛 Bug Fix

Changes

  • litellm/proxy/proxy_server.py — add a helper that gates sensitive callback env var values behind the full-admin role, using SENSITIVE_DATA_MASKER.is_sensitive_key plus a small allowlist for keys the segment-keyword masker misses. Thread the role gate through the callback block, the Slack webhook block, and the email alerting block of /get/config/callbacks. Full PROXY_ADMIN behavior is unchanged.
  • tests/test_litellm/proxy/proxy_server/test_routes_config.py — regression tests that pin both the redacted-for-view-only-admin and plaintext-for-full-admin response shapes, plus a body-wide grep assertion that no fixture value survives anywhere in the response.
  • tests/test_litellm/proxy/test_proxy_server.py + tests/test_litellm/test_router_retry_policy_update.py — update pre-existing test fixtures that previously bypassed auth via MagicMock() to pass an explicit PROXY_ADMIN identity so they exercise the intended plaintext path.
  • tests/proxy_unit_tests/test_proxy_server.py — align pre-existing assertion in test_get_config_callbacks_environment_variables with the new redaction contract (the fixture caller resolves as non-admin under client_no_auth).

Note

Medium Risk
Security-sensitive authorization/redaction on an admin config API; behavior change is role-scoped with broad test coverage, but misclassified keys could still leak or over-redact.

Overview
Closes an information-disclosure gap on GET /get/config/callbacks: callers who are not full PROXY_ADMIN (e.g. PROXY_ADMIN_VIEW_ONLY) now get "REDACTED" for sensitive callback/alerting env values instead of plaintext secrets.

The handler wires in UserAPIKeyAuth, treats only PROXY_ADMIN as full admin, and applies _redact_callback_env_vars to each callback’s variables, plus parallel redaction for Slack (SLACK_WEBHOOK_URL, alerts_to_webhook) and email alerting env vars. Non-sensitive routing fields (hosts, endpoints, ports) stay visible. Full admins still receive real values so the Admin UI can round-trip edits.

is_sensitive_callback_key replaces the private _is_sensitive_callback_var helper (optional extra key set for env names the generic masker misses, e.g. OTEL_HEADERS, SLACK_WEBHOOK_URL). Tests pin view-only vs full-admin response shapes and update fixtures that previously mocked auth without a role.

Reviewed by Cursor Bugbot for commit 3802bdb. Bugbot is set up for automated code reviews on this repo. Configure here.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing litellm_veria_440_admin_viewer_secrets (181cd6a) with litellm_internal_staging (5d4bb75)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (a0b26d2) during the generation of this report, so 5d4bb75 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR applies security hardening to /get/config/callbacks by gating sensitive credential values behind the full PROXY_ADMIN role — callers with lesser roles (e.g. PROXY_ADMIN_VIEW_ONLY) now receive "REDACTED" in place of sensitive values, while non-sensitive routing fields remain visible. It closes the same class of credential-exposure gap that PR #30587 addressed on sibling endpoints.

  • Introduces _redact_callback_env_vars in proxy_server.py and promotes is_sensitive_callback_key to a public helper in callback_utils.py; redaction is applied to callback variables, Slack alerts_to_webhook URLs, and the email alerting block, all gated on user_role == PROXY_ADMIN.
  • Adds four new regression tests covering view-only vs. full-admin response shapes (including body-wide grep assertions that no fixture secret survives), and updates existing fixtures that bypassed auth with MagicMock() to use explicit PROXY_ADMIN identity so the plaintext path is properly exercised.

Confidence Score: 5/5

Safe to merge — the role gate is correctly placed, the redaction helper handles None values cleanly, and both the redacted and plaintext paths are pinned by new regression tests.

The role check is a strict equality on LitellmUserRoles.PROXY_ADMIN, so every non-full-admin role is covered by default. The _redact_callback_env_vars helper correctly passes None values through unchanged and applies the same is_sensitive_callback_key logic already used for at-rest encryption. Previously flagged gaps (email alerting block, Slack variables, GCS_PATH_SERVICE_ACCOUNT) are all addressed in this push. Test fixtures that previously short-circuited auth with a bare MagicMock() now carry an explicit role, so regressions on the plaintext path would be caught.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/proxy_server.py Adds _redact_callback_env_vars helper and gates /get/config/callbacks sensitive values behind PROXY_ADMIN role; covers callback variables, Slack webhook URLs, and email alerting fields correctly.
litellm/proxy/common_utils/callback_utils.py Promotes private _is_sensitive_callback_var to the public is_sensitive_callback_key with an optional extra set; _EXTRA_SENSITIVE_CALLBACK_KEYS now matched case-insensitively via .lower(), consistent with existing usage.
tests/test_litellm/proxy/proxy_server/test_routes_config.py Adds four comprehensive regression tests: view-only admin redaction, full-admin plaintext, Slack webhook URL redaction, email alerting redaction — plus body-wide grep assertions that no fixture secret survives in the response.
tests/test_litellm/proxy/test_proxy_server.py Updates four test fixtures from bare MagicMock() auth overrides to explicit PROXY_ADMIN identity so they correctly exercise the plaintext path and don't silently rely on undefined mock attributes.
tests/proxy_unit_tests/test_proxy_server.py Updates test_get_config_callbacks_environment_variables assertions to expect "REDACTED" for LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, and OTEL_HEADERS under the client_no_auth (non-admin) fixture — consistent with the new redaction contract.
tests/test_litellm/test_router_retry_policy_update.py Updates get_config() call to pass an explicit PROXY_ADMIN UserAPIKeyAuth so the retry-policy read-back test still receives plaintext router settings rather than a redacted or error response.

Reviews (5): Last reviewed commit: "fix(proxy): tighten role gating on /get/..." | Re-trigger Greptile

Comment thread litellm/proxy/proxy_server.py Outdated
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.52941% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/proxy_server.py 68.96% 9 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a redaction layer to the /get/config/callbacks endpoint so non-PROXY_ADMIN callers receive "REDACTED" in place of credential-bearing callback env var values and Slack webhook URLs, while full admins continue to see plaintext. The change is scoped to the response path and does not touch the storage or auth layer.

  • Adds _redact_callback_env_vars helper that uses SENSITIVE_DATA_MASKER.is_sensitive_key plus an explicit _EXTRA_SECRET_CALLBACK_ENV_VARS allowlist (OTEL_HEADERS, GENERIC_LOGGER_HEADERS) for names the segment-keyword masker misses; null values are passed through unchanged so the UI can distinguish "not configured" from "configured but redacted".
  • Adds user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth) to get_config to surface the caller's role; the existing dependencies=[Depends(user_api_key_auth)] decorator means FastAPI's dependency cache calls the function only once, so no double-authentication occurs.
  • Four regression tests cover the view-only-admin redacted shape, full-admin plaintext round-trip, webhook URL redaction, and direct helper behavior.

Confidence Score: 4/5

Safe to merge. The redaction logic is correct and fail-closed: any non-PROXY_ADMIN role (including None) gets credentials redacted. FastAPI's dependency cache ensures user_api_key_auth is called only once despite the double Depends pattern.

The core redaction is sound and well-tested. Two gaps exist: GCS_PATH_SERVICE_ACCOUNT is treated as sensitive by the encryption path but not by the new env-var redaction allowlist, and the email alerting block is left with only partial asterisk masking for view-only admins while the callback and webhook blocks are fully redacted. Neither gap is introduced by this PR's own changes (the email masking was pre-existing), but the callback/webhook fix creates a visible inconsistency in the same response object.

The email alerting variable block in litellm/proxy/proxy_server.py (lines ~14732–14750) deserves a second look for consistency with the new callback redaction pattern.

Important Files Changed

Filename Overview
litellm/proxy/proxy_server.py Adds _redact_callback_env_vars helper and wires it into get_config for non-admin callers; logic is correct and fail-closed (None role → redacted). LANGFUSE_PUBLIC_KEY is redacted as a side effect of the name containing 'key' — intentional per the PR description and tests.
tests/test_litellm/proxy/proxy_server/test_routes_config.py Four new mock-only tests covering view-only admin redaction, full-admin plaintext, webhook URL redaction, and the helper directly. No real network calls; test logic is correct and assertions are specific.

Reviews (2): Last reviewed commit: "test(proxy): align test_get_config_callb..." | Re-trigger Greptile

Comment thread litellm/proxy/proxy_server.py Outdated
Comment thread litellm/proxy/proxy_server.py Outdated
yucheng-berri added a commit that referenced this pull request Jun 30, 2026
…unt path on /get/config/callbacks

Greptile review feedback on PR #31745:
- Email alerting block in the same response used mask_sensitive_keys unconditionally; SMTP_USERNAME came back verbatim to view-only admins and SMTP_PASSWORD got a partial-asterisk prefix/suffix mask rather than full redaction. Same role gate as the callback + Slack webhook blocks now applies: view-only admins get 'REDACTED' for both credential halves; non-secret routing fields (SMTP_HOST, SMTP_PORT, SMTP_SENDER_EMAIL, TEST_EMAIL_ADDRESS, EMAIL_LOGO_URL, EMAIL_SUPPORT_CONTACT) stay visible. Full PROXY_ADMIN continues to see the previous mask_sensitive_keys output so the edit form round-trips.

- GCS_PATH_SERVICE_ACCOUNT mirrors callback_utils._EXTRA_SENSITIVE_CALLBACK_KEYS, which already flags 'gcs_path_service_account' for the encryption path. Adding the env-var-cased name to _EXTRA_SECRET_CALLBACK_ENV_VARS keeps the two lists in sync so the leak does not silently re-open if a GCS-backed callback is later wired into AllCallbacks.litellm_callback_params.

LANGFUSE_PUBLIC_KEY redaction noted by Greptile is intentional and kept: it is half of an SMTP-style credential pair (Langfuse uses Basic Auth with public+secret) and identifies which Langfuse project the proxy logs to. The conservative default-deny on segment-keyword matches is the same posture as PR #30587.
@yucheng-berri

yucheng-berri commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai re-review please. Latest push addresses two of the three P2s; left a reply on the third explaining why the current behavior is intentional.

yucheng-berri added a commit that referenced this pull request Jul 1, 2026
…unt path on /get/config/callbacks

Greptile review feedback on PR #31745:
- Email alerting block in the same response used mask_sensitive_keys unconditionally; SMTP_USERNAME came back verbatim to view-only admins and SMTP_PASSWORD got a partial-asterisk prefix/suffix mask rather than full redaction. Same role gate as the callback + Slack webhook blocks now applies: view-only admins get 'REDACTED' for both credential halves; non-secret routing fields (SMTP_HOST, SMTP_PORT, SMTP_SENDER_EMAIL, TEST_EMAIL_ADDRESS, EMAIL_LOGO_URL, EMAIL_SUPPORT_CONTACT) stay visible. Full PROXY_ADMIN continues to see the previous mask_sensitive_keys output so the edit form round-trips.

- GCS_PATH_SERVICE_ACCOUNT mirrors callback_utils._EXTRA_SENSITIVE_CALLBACK_KEYS, which already flags 'gcs_path_service_account' for the encryption path. Adding the env-var-cased name to _EXTRA_SECRET_CALLBACK_ENV_VARS keeps the two lists in sync so the leak does not silently re-open if a GCS-backed callback is later wired into AllCallbacks.litellm_callback_params.

LANGFUSE_PUBLIC_KEY redaction noted by Greptile is intentional and kept: it is half of an SMTP-style credential pair (Langfuse uses Basic Auth with public+secret) and identifies which Langfuse project the proxy logs to. The conservative default-deny on segment-keyword matches is the same posture as PR #30587.
@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch from 181cd6a to 8359532 Compare July 1, 2026 20:07
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch from 8359532 to 4a7a7a2 Compare July 1, 2026 20:13
@yucheng-berri yucheng-berri changed the title fix(proxy): redact callback env vars and Slack webhook URLs from non-admin /get/config/callbacks (VERIA-440) fix(proxy): tighten role gating on /get/config/callbacks response Jul 1, 2026

@cursor cursor Bot left a comment

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.

✅ 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 8359532. Configure here.

@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch 2 times, most recently from 11347e3 to c4b41ec Compare July 1, 2026 21:06
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch from c4b41ec to 854ccd8 Compare July 1, 2026 21:15
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai re-review please. Latest push refactors the sensitivity classifier to reuse the existing helper in callback_utils.py and fixes a ruff-format nit.

@cursor cursor Bot left a comment

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.

✅ 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 c4b41ec. Configure here.

@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch 2 times, most recently from 2d3d7e5 to 3802bdb Compare July 1, 2026 21:39
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai re-review please. Latest push closes the remaining Slack variables gap that the last review flagged, adds SLACK_WEBHOOK_URL to the shared allowlist, and extends the regression tests to pin both shapes.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

✅ 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 3802bdb. Configure here.

@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch from 3802bdb to 7201006 Compare July 1, 2026 21:46
The handler returned decrypted callback environment values and alerting
routing values verbatim to callers who were not full PROXY_ADMIN. Gate
those on full-admin role, matching the posture used on the sibling
config-inspection endpoints. Non-sensitive routing fields (host / base
URL / port style values) stay visible so the UI can still label which
integration is wired up. Full PROXY_ADMIN sees everything unchanged so
the edit form round-trips on save.

Resolves LIT-4115.
@yucheng-berri
yucheng-berri force-pushed the litellm_veria_440_admin_viewer_secrets branch from 7201006 to 054e6c1 Compare July 2, 2026 00:20
@yucheng-berri
yucheng-berri merged commit 8ce6b4d into litellm_internal_staging Jul 2, 2026
123 checks passed
@yucheng-berri
yucheng-berri deleted the litellm_veria_440_admin_viewer_secrets branch July 2, 2026 00:58
duanhongyi pushed a commit to duanhongyi/litellm that referenced this pull request Jul 2, 2026
…rriAI#31745)

The handler returned decrypted callback environment values and alerting
routing values verbatim to callers who were not full PROXY_ADMIN. Gate
those on full-admin role, matching the posture used on the sibling
config-inspection endpoints. Non-sensitive routing fields (host / base
URL / port style values) stay visible so the UI can still label which
integration is wired up. Full PROXY_ADMIN sees everything unchanged so
the edit form round-trips on save.

Resolves LIT-4115.
Rodrigo-Palma pushed a commit to Rodrigo-Palma/litellm that referenced this pull request Jul 3, 2026
…rriAI#31745)

The handler returned decrypted callback environment values and alerting
routing values verbatim to callers who were not full PROXY_ADMIN. Gate
those on full-admin role, matching the posture used on the sibling
config-inspection endpoints. Non-sensitive routing fields (host / base
URL / port style values) stay visible so the UI can still label which
integration is wired up. Full PROXY_ADMIN sees everything unchanged so
the edit form round-trips on save.

Resolves LIT-4115.
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.

2 participants