Litellm clean litellm oss staging 04 01 2026 - #25856
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
There was a problem hiding this comment.
Medium: Weaker secret redaction patterns in exception-to-HTTP-response path
This PR introduces a new secret_redaction.py module and applies it to exception messages that eventually surface in HTTP error responses. The new module's regex set is narrower than the existing one in _logging.py — it omits PEM private key blocks, GCP OAuth2 tokens (ya29.*), raw JWTs (eyJ...), Azure SAS tokens, and service-account JSON blobs. Secrets matching those patterns in provider error messages would not be redacted before reaching clients.
- medium: incomplete secret redaction in exception responses — litellm/litellm_core_utils/secret_redaction.py
| r"database_connection_string|" | ||
| r"huggingface_token|jwt_secret)" | ||
| r"""['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+""", | ||
| ] |
There was a problem hiding this comment.
Medium: Missing redaction patterns compared to logging path
This module is used to redact secrets in exception messages that reach HTTP responses (exception_mapping_utils.py). Several credential patterns present in _logging.py are absent here: PEM private key blocks, GCP OAuth2 tokens (ya29.*), raw JWTs (eyJ...), Azure SAS tokens (sig=...), client_secret/azure_password space-separated formats, and service-account JSON blobs. An attacker triggering a provider error whose message contains one of these patterns would receive the secret in the HTTP 4xx/5xx response body.
Consider keeping both regex sets in sync, or importing a shared set of patterns.
Greptile SummaryThis PR bundles several independent improvements: adds Crusoe as an OpenAI-compatible provider (JSON registry, model pricing, docs, tests), refactors secret-pattern redaction into a standalone Previously flagged issues (import syntax error in Confidence Score: 5/5Safe to merge; previously flagged blocking issues (import syntax error, missing comma, NameError on _apply_gemini_3_metadata) are all resolved in this revision. All P0/P1 issues noted in prior review threads appear fixed. The only remaining finding is a P2 TypedDict annotation inconsistency that carries no runtime risk. Changes are additive and well-tested. litellm/litellm_core_utils/secret_redaction.py — pattern set still diverges from the original _logging.py list (previously flagged; no new regression).
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/secret_redaction.py | New module extracts secret-redaction logic from _logging.py; pattern set is slightly expanded (URL query-param key= pattern added) but still diverges from _logging.py's original list (previously flagged in thread) |
| litellm/llms/vertex_ai/gemini/transformation.py | Adds Gemini Files API URI branch; calls _apply_gemini_metadata (exists at line 136 — previous NameError concern is resolved); uri-only file_data path uses cast to bypass TypedDict's required mime_type field |
| litellm/types/guardrails.py | Adds QostodianNexus import and enum entry; previously flagged syntax error (unclosed paren) and missing comma in LitellmParams bases appear fixed in current diff |
| litellm/proxy/utils.py | Adds LEFT JOIN to LiteLLM_BudgetTable for team-member budget to surface per-member RPM/TPM limits; aligned with existing UserAPIKeyAuth fields |
| litellm/llms/azure/azure.py | One-line fix: forwards api_version to aembedding() in async embedding path; regression test added |
| litellm/proxy/guardrails/guardrail_hooks/qohash/qohash.py | New Qostodian Nexus guardrail; correctly overrides apply_guardrail in class dict for unified routing detection |
| tests/test_litellm/test_secret_redaction.py | Tests migrated from _redact_string to redact_string; existing assertions are behaviorally equivalent |
| litellm/llms/azure/cost_calculation.py | Adds service_tier parameter propagation through Azure cost calculator; clean additive change |
Reviews (10): Last reviewed commit: "Unify secret redaction patterns" | Re-trigger Greptile
| from litellm.types.proxy.guardrails.guardrail_hooks.hiddenlayer import ( | ||
| HiddenlayerGuardrailConfigModel | ||
| from litellm.types.proxy.guardrails.guardrail_hooks.qohash import ( | ||
| QostodianNexusConfigModel, | ||
| ) |
There was a problem hiding this comment.
SyntaxError: '(' was never closed — file cannot be imported
The closing ) for the HiddenlayerGuardrailConfigModel import was not inserted before the new qohash import, so Python still sees an open parenthesis when it hits the second from. Running python -c "import litellm.types.guardrails" reproduces the error immediately, which means every proxy startup that touches guardrail types will crash.
| from litellm.types.proxy.guardrails.guardrail_hooks.hiddenlayer import ( | |
| HiddenlayerGuardrailConfigModel | |
| from litellm.types.proxy.guardrails.guardrail_hooks.qohash import ( | |
| QostodianNexusConfigModel, | |
| ) | |
| from litellm.types.proxy.guardrails.guardrail_hooks.hiddenlayer import ( | |
| HiddenlayerGuardrailConfigModel, | |
| ) | |
| from litellm.types.proxy.guardrails.guardrail_hooks.qohash import ( | |
| QostodianNexusConfigModel, | |
| ) |
| BlockCodeExecutionGuardrailConfigModel, | ||
| HiddenlayerGuardrailConfigModel | ||
| QostodianNexusConfigModel, |
There was a problem hiding this comment.
Missing comma in
LitellmParams class bases
HiddenlayerGuardrailConfigModel on line 772 has no trailing comma before QostodianNexusConfigModel. Python class definitions require comma-separated base classes; without it the parser errors out, preventing the class from being defined.
| BlockCodeExecutionGuardrailConfigModel, | |
| HiddenlayerGuardrailConfigModel | |
| QostodianNexusConfigModel, | |
| HiddenlayerGuardrailConfigModel, | |
| QostodianNexusConfigModel, |
| def _build_secret_patterns() -> "re.Pattern[str]": | ||
| patterns: List[str] = [ | ||
| # AWS access key IDs | ||
| r"(?:AKIA|ASIA)[0-9A-Z]{16}", | ||
| # AWS secrets / session tokens / access key IDs (key=value) | ||
| r"(?:aws_secret_access_key|aws_session_token|aws_access_key_id)" | ||
| r"\s*[:=]\s*[A-Za-z0-9/+=]{20,}", | ||
| # Bearer tokens (OAuth, JWT, etc.) | ||
| r"Bearer\s+[A-Za-z0-9\-._~+/]{10,}=*", | ||
| # Basic auth headers | ||
| r"Basic\s+[A-Za-z0-9+/]{10,}={0,2}", | ||
| # OpenAI / Anthropic sk- prefixed keys | ||
| r"sk-[A-Za-z0-9\-_]{20,}", | ||
| # Generic api_key / api-key / apikey (handles 'key': 'value' dict repr) | ||
| r"(?:api[_-]?key)['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]{8,}", | ||
| # x-api-key / api-key header values (handles 'key': 'value' dict repr) | ||
| r"(?:x-api-key|api-key)['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+", | ||
| # Anthropic internal header keys | ||
| r"x-ak-[A-Za-z0-9\-_]{20,}", | ||
| # Google API keys (bare key value) | ||
| r"AIza[0-9A-Za-z\-_]{35}", | ||
| # URL query-param key=VALUE (e.g. ?key=AIza... or &key=...) — catches the | ||
| # full "key=<secret>" fragment so the value is redacted regardless of format. | ||
| r"(?<=[?&])key=[^\s&'\"]{8,}", | ||
| # Password / secret params (handles key=value and 'key': 'value') | ||
| r"\w*(?:password|passwd|client_secret|secret_key|_secret)" | ||
| r"['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+", | ||
| # Database connection string credentials (scheme://user:pass@host) | ||
| r"(?<=://)[^\s'\"]*:[^\s'\"@]+(?=@)", | ||
| # Databricks personal access tokens | ||
| r"dapi[0-9a-f]{32}", | ||
| # ── Key-name-based redaction ── | ||
| # Catches secrets inside dicts/config dumps by matching on the KEY name | ||
| # regardless of what the value looks like. | ||
| # e.g. 'master_key': 'any-value-here', "database_url": "postgres://..." | ||
| r"(?:master_key|database_url|db_url|connection_string|" | ||
| r"private_key|signing_key|encryption_key|" | ||
| r"auth_token|access_token|refresh_token|" | ||
| r"slack_webhook_url|webhook_url|" | ||
| r"database_connection_string|" | ||
| r"huggingface_token|jwt_secret)" | ||
| r"""['\"]?\s*[:=]\s*['\"]?[^\s,'\"})\]{}>]+""", | ||
| ] |
There was a problem hiding this comment.
secret_redaction.py pattern set is smaller than _logging.py
_logging.py's _build_secret_patterns() includes patterns not present here: PEM private-key blocks, GCP OAuth2 tokens (ya29.*), Azure SAS tokens (sig=...), raw JWTs (eyJ…), and JSON service-account blobs. When exception_mapping_utils.py calls redact_string from this module, those secret shapes won't be scrubbed from exception messages even though the logging filter (SecretRedactionFilter) would have caught them in log output.
Consider either (a) merging these two functions into a single authoritative pattern list, or (b) having _logging.py's _redact_string delegate to this module's redact_string so the two sinks stay in sync.
Replace hand-written CrusoeChatConfig class and manual registrations across constants.py, __init__.py, get_llm_provider_logic.py, and _lazy_imports_registry.py with a single entry in litellm/llms/openai_like/providers.json, consistent with the recommended pattern for OpenAI-compatible providers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…_init__.py - Remove trailing slash from docs Base URL to match providers.json - Wrap model_cost mutations in try/finally to prevent test state leakage - Add missing __init__.py to crusoe test package
The backup JSON was missing Crusoe model entries, causing test_crusoe_model_list_populated to fail with AssertionError. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-Thinking These are reasoning/thinking models but were missing the flag, causing litellm.supports_reasoning() to return False and reasoning-token handling to not activate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Crusoe's vLLM-based endpoint accepts max_tokens, not max_completion_tokens. Without this mapping, callers using the OpenAI-standard param would get errors.
…indentation Trailing slashes on custom API base examples cause double-slash in get_complete_url. Also fixes inconsistent list indentation in test_crusoe_models_configuration.
The previous example set CRUSOE_API_BASE via env var and also passed api_base= in the same call, making it look like both were required. They are independent alternatives.
… Gemma 3 - Streaming example referenced Llama-3.1 instead of Llama-3.3 - Add supports_vision: true for gemma-3-12b-it in both JSON files, matching other providers (bedrock, novita)
9cb2b6a to
99d075d
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Password regex missing word boundary causes quadratic backtracking
- Added the same start-or-nonword anchor to the shared password secret pattern to avoid quadratic backtracking on long word-character runs.
- ✅ Fixed: Duplicated secret patterns diverge from canonical implementation
- Moved the canonical secret patterns into the shared redaction utility and made logging delegate to it so exception and logging paths stay consistent.
You can send follow-ups to the cloud agent here.
|
bugbot run |
There was a problem hiding this comment.
✅ 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 97cfb4f. Configure here.
…itellm_clean_litellm_oss_staging_04_01_2026
…ss_staging_04_01_2026 Litellm clean litellm oss staging 04 01 2026
Relevant issues
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/test_litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
Type
🆕 New Feature
🐛 Bug Fix
🧹 Refactoring
📖 Documentation
🚄 Infrastructure
✅ Test
Changes
Note
Medium Risk
Touches security-adjacent areas (secret redaction + exception messages) and proxy auth/rate-limit data plumbing, which could affect logging output and request limiting behavior if misconfigured. Most changes are additive and covered by new unit tests, but they span multiple critical paths.
Overview
Adds Crusoe as an OpenAI-compatible provider (JSON registry entry, endpoint support metadata, model pricing/context entries, and new provider docs) plus tests to validate provider detection, env/param config, and model cost map population.
Refactors secret redaction by moving the compiled regex +
redact_string()into a new core utility module and reusing it from logging and exception mapping so exception strings/messages are also scrubbed.Extends cost calculation to propagate
service_tierthrough Azure and Azure AI calculators (with new tests for tiered pricing), forwardsapi_versionthrough the Azure embedding async path (regression fix), and updates Gemini media handling to support Gemini Files API URIs without attempting HTTP MIME-type resolution.Introduces a new proxy guardrail integration for Qohash Qostodian Nexus (hook + config model + UI mapping/logo) and enhances proxy token lookup to join team-member budget limits so v3 rate limiting can enforce team-member RPM/TPM (with a new 429 test case).
Reviewed by Cursor Bugbot for commit 97cfb4f. Bugbot is set up for automated code reviews on this repo. Configure here.