flawopen.com/AI Security/berriai-litellm-ghsa-7hp6-salt-key-session-token-privilege-escalation
LiteLLM Salt-Key Privilege Escalation: GHSA-7hp6-4w63-5g45
LiteLLM reused its secret-encryption path for UI and CLI session tokens. A low-privilege internal_user could make attacker-controlled identity data pass through that shared path and reach proxy_admin; the role could then access MCP stdio command execution. The maintainer fixed token typing with a dedicated prefix and AES-GCM authenticated context. No CVE or confirmed in-the-wild exploitation is reported.[1], [2]
A building uses the same stamp to seal a storage envelope and issue an administrator's access badge. A visitor can influence what goes into the envelope, and a guard later mistakes that sealed envelope for a genuine badge. LiteLLM's fix gives session badges a distinct label and cryptographically binds that label to the seal, so a stored-secret envelope cannot pass as a login token.[1], [2]
Core Concepts & Subsystem Terms
Salt key- LiteLLM's configured key material used by its encryption helpers. This issue involved using the same underlying key path for stored values and bearer session tokens without binding the ciphertext to its intended purpose.[1], [2]
Authenticated additional data (AAD)- Data such as a token-type prefix that AES-GCM authenticates alongside ciphertext. AAD is not encrypted, but changing or omitting it makes authentication fail.[2]
internal_user and proxy_admin- LiteLLM roles. The advisory says an authenticated internal_user could escalate to proxy_admin, the administrative role.[1]
MCP stdio- A Model Context Protocol transport that starts a local process and exchanges messages through standard input and output. LiteLLM says the resulting proxy_admin access could reach command execution through this endpoint.[1]
Framework mappings
- FlawOpen’s conceptual mapping to MITRE CWE; no vendor or CVE record assigned this weakness ID to this research demonstration. CWE-345
Step-by-Step Attack Flow
A low-privilege account reaches key management
The advisory's starting condition is an authenticated LiteLLM internal_user. Unauthenticated access is not required, but the actor must already hold that role.[1]
Metadata ciphertext is created under the shared value-encryption path
The advisory says crafted identity data in API-key metadata could be encrypted and returned through key generation. The issue is the later acceptance of that ciphertext as another token type; do not treat arbitrary metadata as an independent login.[1], [2]
Administrative access reaches MCP stdio
With proxy_admin privileges, the advisory says the actor could execute commands through the MCP stdio endpoint. This is host-side process capability, not a command run by the language model itself.[1]
Root Cause Analysis
BerriAI's advisory GHSA-7hp6-4w63-5g45 describes a cross-purpose authentication failure. LiteLLM used its value-encryption helper for both stored secrets and UI/CLI bearer session tokens, while session authentication decrypted values using the same key path. An internal_user could request an API key whose metadata contained attacker-controlled serialized identity data; the management path encrypted and returned the metadata value. When that ciphertext was presented as a bearer token, the session path could decrypt and interpret the forged proxy_admin identity. That role could then reach MCP stdio command execution. The upstream fix at f7cd90f changes token creation and verification: tokens use the litellm_login_ prefix, AES-GCM authenticated additional data (AAD) bound to that prefix, and a token-specific decryptor. The salt key remains key material; the security boundary is the cryptographically authenticated token purpose and the distinct parser path. Stored-value ciphertext therefore does not validate as a session token. The advisory rates the issue CVSS 3.1 9.9 Critical, says versions after 1.91.0 are affected by default, and says 1.87.0–1.90.x are affected only when EXPERIMENTAL_UI_LOGIN=true. It lists fixed versions 1.100.4, 1.101.3, 1.102.2, 1.103.1, and 1.104.0rc2 on their respective branches. The temporary mitigation EXPERIMENTAL_UI_LOGIN=false disables the vulnerable login path but also breaks CLI SSO and Claude Code gateway login. The advisory says no CVE is known. It does not establish exploitation in the wild. The code pair below shows the authentication-domain change from the upstream patch; it is not an exploit or a full replacement for the surrounding authentication implementation.[1], [2], [3], [4]
Source Code: Flaw vs. Secure Implementation
The upstream patch replaces the generic value encryptor/decryptor at both session-token creation and authentication. encrypt_bearer_token authenticates the token prefix as AES-GCM AAD; decrypt_bearer_token requires that prefix and the same AAD, so a value encrypted for storage cannot be reinterpreted as a login token. This is a reduced excerpt from the cited commit, not standalone authentication code. The shared salt key is not itself proof of a unique key per purpose; the verified separation shown here is the authenticated token type and matching decoder.[2], [3]
Source excerpt: litellm/proxy/auth/auth_checks.py and litellm/proxy/common_utils/encrypt_decrypt_utils.py — reduced excerpts from upstream commit f7cd90f
# Before the patch: stored-value ciphertext was also minted as a session token.
return encrypt_value_helper(valid_token.model_dump_json(exclude_none=True))
# Session authentication decrypted through the generic value helper.
decrypted_token = decrypt_value_helper(hashed_token, key="ui_hash_key")
# After the patch: session tokens have a dedicated type and AAD.
LITELLM_SESSION_TOKEN_PREFIX = "litellm_login_"
return encrypt_bearer_token(
valid_token.model_dump_json(exclude_none=True),
prefix=LITELLM_SESSION_TOKEN_PREFIX,
)
# Authentication uses the matching purpose-specific decoder.
decrypted_token = decrypt_bearer_token(
hashed_token, prefix=LITELLM_SESSION_TOKEN_PREFIX
)
Engineering & System Hardening Checklist
- ✓Upgrade each LiteLLM deployment to a fixed version on its release line: 1.100.4, 1.101.3, 1.102.2, 1.103.1, or 1.104.0rc2; verify current vendor guidance and the resolved package or image rather than relying on a floating tag.[1], [3], [4]
- ✓For versions 1.87.0–1.90.x, verify whether EXPERIMENTAL_UI_LOGIN was enabled; the advisory says those versions are affected only when it was explicitly true.[1]
- ✓If an immediate upgrade is impossible, set
EXPERIMENTAL_UI_LOGIN=falseas a temporary mitigation and plan for the documented loss of CLI SSO and Claude Code gateway login.[1] - ✓Add a regression test proving stored-value ciphertext is rejected by the session-token decoder, while a valid, unexpired LiteLLM-minted session token remains accepted.[2]
- ✓Keep ciphertext purpose-bound: use a dedicated token prefix and authenticate that prefix as AES-GCM AAD at both minting and verification; do not accept a generic decrypt helper's output as an identity token.[2]
- ✓Restrict access to API-key management and MCP stdio configuration to the roles that require it, and run the proxy with least operating-system privilege.[1]
- ✓FlawOpen analysis: Instrument the deployment’s auth audit to record principal, resolved role, token type, timestamp, and request ID while omitting bearer tokens and ciphertext; test the event schema. Add an alert test for LiteLLM proxy processes starting MCP stdio children, then correlate auth and process events during an investigation. These are deployment-side detection recommendations, not vendor-confirmed log signals.
- ✓Track this as GHSA-7hp6-4w63-5g45: no CVE is listed in the maintainer advisory, and the reviewed sources do not confirm exploitation in the wild.[1]
Sources
- BerriAI LiteLLM security advisory GHSA-7hp6-4w63-5g45
- LiteLLM upstream session-token fix f7cd90f
- LiteLLM v1.100.4 release notes: UI and CLI session-token format
- LiteLLM v1.104.0 release notes: session-token format and upgrade behavior
- MITRE CWE-345: Insufficient Verification of Data Authenticity
- MITRE CWE-269: Improper Privilege Management
- MITRE CWE-441: Unintended Proxy or Intermediary