Skip to content

fix(proxy): resolve os.environ/ refs for all AWS auth params in DB-sourced models - #32256

Merged
yuneng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_bedrock_db_env_expansion
Jul 6, 2026
Merged

fix(proxy): resolve os.environ/ refs for all AWS auth params in DB-sourced models#32256
yuneng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_bedrock_db_env_expansion

Conversation

@yucheng-berri

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Pre-Submission checklist

  • 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

Screenshots / Proof of Fix

The customer reported that after upgrading from 1.89.1 to 1.91.0, a model stored in the DB with aws_role_name: os.environ/BEDROCK_ASSUME_ROLE_ARN stopped working. STS returns ValidationError: os.environ/BEDROCK_ASSUME_ROLE_ARN is invalid because the literal string reaches AssumeRole instead of the resolved ARN.

The proof-of-fix curls a proxy connected to a real Postgres, with a DB row shaped like the customer's:

model_id        | bedrock-repro-1
model_name      | bedrock-claude
litellm_params  | {"model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0",
                   "aws_role_name": "os.environ/BEDROCK_ASSUME_ROLE_ARN",
                   "aws_region_name": "us-east-1"}
BEDROCK_ASSUME_ROLE_ARN=arn:aws:iam::111111111111:role/some-bedrock-role

Before (unfixed 1.91.x): the router receives the literal os.environ/... string and forwards it to STS

$ curl -sS http://localhost:4000/model/info -H 'Authorization: Bearer sk-1234' | jq '.data[] | select(.model_name=="bedrock-claude") | .litellm_params'
{
  "aws_region_name": "us-east-1",
  "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0",
  "aws_role_name": "os.environ/BEDROCK_ASSUME_ROLE_ARN"
}

$ curl -sS -w "\nHTTP=%{http_code}\n" http://localhost:4000/v1/chat/completions \
    -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
    -d '{"model":"bedrock-claude","messages":[{"role":"user","content":"hi"}]}'

The traceback shows _auth_with_aws_role was called with the literal string as RoleArn, so sts_client.assume_role(RoleArn="os.environ/BEDROCK_ASSUME_ROLE_ARN", ...) fires and STS rejects it. In this repro the fake AWS creds trip InvalidClientTokenId first, but the customer's real AWS creds get past that check and hit the exact ValidationError: ... is invalid they reported

After (with this PR): the router receives the resolved ARN, and STS receives a well-formed value

$ curl -sS http://localhost:4000/model/info -H 'Authorization: Bearer sk-1234' | jq '.data[] | select(.model_name=="bedrock-claude") | .litellm_params'
{
  "aws_region_name": "us-east-1",
  "model": "bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0",
  "aws_role_name": "arn:aws:iam::111111111111:role/some-bedrock-role"
}

LIT-3831 stays closed: an attacker sending aws_role_name: os.environ/DATABASE_URL in the HTTP request body is still refused by the existing _BANNED_REQUEST_BODY_PARAMS gate

$ curl -sS -w "\nHTTP=%{http_code}\n" http://localhost:4000/v1/chat/completions \
    -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
    -d '{"model":"bedrock-claude","messages":[{"role":"user","content":"hi"}],"aws_role_name":"os.environ/DATABASE_URL"}'
{"error":{"message":"Authentication Error, Rejected Request: aws_role_name is not allowed in request body. ..."}}
HTTP=401

Team-scoped DB models still get resolve_env_refs=False, matching the LIT-3831 defense-in-depth contract for the team-scoped DB path (see the regression test test_ProxyConfig__add_deployment_keeps_team_aws_env_refs_literal)

Type

🐛 Bug Fix

Changes

Root cause: PR #30867 (LIT-3831) removed the per-request os.environ/ expansion inside BaseAWSLLM.get_credentials. That is only safe if the config-load path pre-resolves os.environ/ refs, so the value reaching get_credentials is already the real secret. The YAML config path has always done this. The DB-load path (ProxyConfig._resolve_db_litellm_param in litellm/proxy/proxy_server.py) only re-expands keys in _DB_LITELLM_PARAM_ENV_REF_KEYS, which covered api_key, client_secret, vertex_credentials, vertex_ai_credentials, aws_access_key_id, and aws_secret_access_key, but none of the other AWS auth fields. A model row like aws_role_name: os.environ/BEDROCK_ASSUME_ROLE_ARN lands on the router with the literal string, get_credentials no longer expands it, and STS rejects the AssumeRole call

Fix: extend _DB_LITELLM_PARAM_ENV_REF_KEYS to cover the remaining nine AWS auth params (aws_session_token, aws_region_name, aws_session_name, aws_profile_name, aws_role_name, aws_web_identity_token, aws_sts_endpoint, aws_external_id, aws_bedrock_runtime_endpoint). Now os.environ/ refs resolve at DB-load time (trusted, server-owned), matching the YAML-config code path. Team-scoped DB rows still get resolve_env_refs=False, so the LIT-3831 team-scoped defense-in-depth path is unchanged and the request-body attack surface stays gated by _BANNED_REQUEST_BODY_PARAMS

Regression tests in tests/test_litellm/proxy/proxy_server/test_proxy_config.py:

  • test_ProxyConfig__add_deployment_resolves_env_refs_for_aws_bedrock_auth_params pins every added field as an os.environ/… DB value and asserts each resolves on the router (mutation-checked; fails on unfixed code with the exact "literal string not resolved" symptom)
  • test_ProxyConfig__add_deployment_keeps_team_aws_env_refs_literal pins that team-scoped DB rows do NOT resolve aws_role_name, guarding the LIT-3831 team path

…urced models

PR #30867 removed request-time os.environ/ expansion in
BaseAWSLLM.get_credentials to close LIT-3831. That relies on config-load
paths pre-resolving os.environ/ refs, but the DB-load path
(_resolve_db_litellm_param) only re-expands keys in
_DB_LITELLM_PARAM_ENV_REF_KEYS, which covered api_key,
aws_access_key_id, and aws_secret_access_key but not the other AWS auth
fields. A model stored in Postgres with e.g.
    aws_role_name: os.environ/BEDROCK_ASSUME_ROLE_ARN
lands on the router with the literal string, get_credentials no longer
expands it, and STS returns
    ValidationError: os.environ/BEDROCK_ASSUME_ROLE_ARN is invalid

Add the remaining AWS auth params to the allowlist so DB-sourced values
resolve at model-load time (trusted, server-side), matching the
YAML-config path. Team-scoped DB rows still get resolve_env_refs=False,
so the LIT-3831 defense-in-depth path is unchanged and request-body
injection is still blocked by _BANNED_REQUEST_BODY_PARAMS.

Regression tests pin every added field as an os.environ/ DB value and
assert it resolves on the router, plus a team-scoped pin that asserts
env refs remain literal.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


yucheng seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where DB-stored AWS auth parameters containing os.environ/ references (e.g. aws_role_name: os.environ/BEDROCK_ASSUME_ROLE_ARN) were not resolved at load time, causing the literal string to reach AWS STS and fail validation. The fix extends _DB_LITELLM_PARAM_ENV_REF_KEYS to cover all remaining AWS auth params, bringing DB-load behavior in line with the YAML-config code path.

  • proxy_server.py: 12 AWS auth fields added to _DB_LITELLM_PARAM_ENV_REF_KEYS; _resolve_db_litellm_param already guards on decrypted_value.startswith(\"os.environ/\") so literal values like \"us-east-1\" are unaffected.
  • Tests: Two new mock-only regression tests cover both the happy path (env refs resolved for global DB models) and the defense-in-depth path (team-scoped DB models leave refs literal).

Confidence Score: 5/5

Safe to merge — additive, narrow change to the DB model loading path with preserved team-scope bypass.

The fix restores load-time resolution of AWS auth env refs in DB-stored models, matching YAML config behavior. LiteLLM_Params uses extra=allow so all new keys are preserved. Team-scoped bypass remains intact and is tested.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/proxy_server.py Extends _DB_LITELLM_PARAM_ENV_REF_KEYS with 12 additional AWS auth params; team-scoped model path is unchanged.
tests/test_litellm/proxy/proxy_server/test_proxy_config.py Adds two targeted mock-only regression tests covering env-ref resolution and team-scoped bypass.

Reviews (3): Last reviewed commit: "fix(proxy): also allow os.environ/ resol..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a regression where DB-stored models with os.environ/ references in AWS auth parameters (e.g. aws_role_name, aws_session_name, aws_sts_endpoint) received unresolved literal strings instead of actual values, because _DB_LITELLM_PARAM_ENV_REF_KEYS only covered aws_access_key_id and aws_secret_access_key.

  • proxy_server.py: Extends _DB_LITELLM_PARAM_ENV_REF_KEYS with the nine missing AWS auth params (aws_session_token, aws_region_name, aws_session_name, aws_profile_name, aws_role_name, aws_web_identity_token, aws_sts_endpoint, aws_external_id, aws_bedrock_runtime_endpoint) — all confirmed as valid fields passed through to BaseAWSLLM.get_credentials.
  • test_proxy_config.py: Adds two targeted regression tests — one verifying that all nine new params resolve for global DB models, and one verifying that team-scoped DB models continue to receive unresolved os.environ/ strings, preserving the existing defense-in-depth boundary.

Confidence Score: 5/5

Safe to merge — minimal, surgical change with comprehensive regression tests covering both the fix and the security boundary it must not cross.

The change is a single frozenset extension in proxy_server.py. Every added key is confirmed to flow directly into BaseAWSLLM.get_credentials or its callers (verified in base_aws_llm.py, converse_handler.py, batches/handler.py). The resolve_env_refs=False guard for team-scoped models is untouched and is explicitly tested by the new regression test. No existing tests are modified, and all new tests use mocks with no real network calls.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/proxy_server.py Extends _DB_LITELLM_PARAM_ENV_REF_KEYS with 9 missing AWS auth params so DB-stored os.environ/ refs resolve at load time, matching the YAML-config path
tests/test_litellm/proxy/proxy_server/test_proxy_config.py Adds two regression tests: one pins that all 9 new AWS params resolve for global DB models, one pins that team-scoped DB models leave os.environ/ refs literal

Reviews (2): Last reviewed commit: "fix(proxy): resolve os.environ/ refs for..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…_id, aws_batch_role_arn, aws_workspace_id

Round out the AWS auth-field coverage of _DB_LITELLM_PARAM_ENV_REF_KEYS
so every stringy aws_* field a deployment can pin in the DB resolves
os.environ/ refs at load time:

- aws_bedrock_project_id: Bedrock project/workspace association, banned
  from request bodies via _BANNED_REQUEST_BODY_PARAMS
- aws_batch_role_arn: Bedrock batches role ARN (analog of aws_role_name)
- aws_workspace_id: Claude Platform workspace ID

Verified against three independent sources:
- BaseAWSLLM.aws_authentication_params (all 11)
- LiteLLM_Params-declared AWS fields (all 5)
- every aws_* string read from litellm_params/kwargs/optional_params
  across litellm/ (all 14, excluding aws_bedrock_client which is a
  boto3 client object, not a string, and aws_polly which is a provider
  name)

The regression test now pins all 12 newly-allowlisted fields.
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@yuneng-berri
yuneng-berri merged commit 7d13f03 into litellm_internal_staging Jul 6, 2026
124 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_bedrock_db_env_expansion branch July 6, 2026 17:27
yucheng-berri added a commit that referenced this pull request Jul 8, 2026
Root cause: PR #30867 removed request-time os.environ/ expansion in
BaseAWSLLM.get_credentials. That is only safe if config-load pre-resolves
os.environ/ refs so the value reaching get_credentials is already the real
secret. The YAML config path has always done this. The DB-load path
(ProxyConfig._resolve_db_litellm_param) only re-expanded keys in a hardcoded
whitelist (_DB_LITELLM_PARAM_ENV_REF_KEYS) plus short-circuited env-ref
resolution entirely for team-scoped rows. PR #32256 extended that whitelist
to 18 keys to unblock a customer whose Bedrock model with aws_role_name:
os.environ/BEDROCK_ASSUME_ROLE_ARN broke on v1.90+, but the whitelist is
structurally fragile: every future auth field breaks the same way until
someone remembers to add it

Fix: remove the whitelist and the team-scope short-circuit. The DB-load
resolver now expands os.environ/ on every string field, matching the YAML
path. Trust boundary stays on the write side: only PROXY_ADMIN can create
team_id=None rows, only team admins of a team can create rows scoped to
that team, and the request-body vector is still blocked by
_BANNED_REQUEST_BODY_PARAMS. Team-scoped rows now resolve env refs — this
is a deliberate LIT-3831 threat-model expansion trusting team admins for
env-var reads

Regression tests in tests/test_litellm/proxy/proxy_server/test_proxy_config.py:
- test_ProxyConfig__add_deployment_resolves_env_refs_after_db_decrypt pins
  admin-scoped rows resolve every field (previously api_base stayed literal)
- test_ProxyConfig__add_deployment_resolves_team_env_refs pins team rows
  resolve env refs (previously stayed literal)
- test_ProxyConfig__add_deployment_resolves_env_refs_on_arbitrary_field pins
  the no-whitelist invariant against a made-up field name
- test_ProxyConfig__add_deployment_resolves_env_refs_for_aws_bedrock_auth_params
  (from #32256) still passes
- Path B counterparts (decrypt_model_list_from_db) mirror the above

Left as followups (not fixed here):
- /model/info and /v2/model/info still echo resolved values for fields not
  in the current pop-list (aws_role_name, aws_sts_endpoint, api_base, etc.).
  Fix is to extend remove_sensitive_info_from_deployment; separate PR
- Master-key rotation reads DB rows via decrypt_model_list_from_db which
  now resolves universally, so rotation collapses env-refs into hardcoded
  values. Pre-existing bug for the 6 previously-whitelisted fields; wider
  surface after this PR. Separate PR
yuneng-berri added a commit that referenced this pull request Jul 8, 2026
chore(release): backport #32256, #32405, #32524 to stable/1.91.x and cut 1.91.1
yuneng-berri added a commit that referenced this pull request Jul 8, 2026
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jul 9, 2026
….1) (#1475)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/berriai/litellm](https://images.chainguard.dev/directory/image/wolfi-base/overview) ([source](https://github.com/BerriAI/litellm)) | patch | `v1.91.0` → `v1.91.1` |

---

### Release Notes

<details>
<summary>BerriAI/litellm (ghcr.io/berriai/litellm)</summary>

### [`v1.91.1`](https://github.com/BerriAI/litellm/releases/tag/v1.91.1)

[Compare Source](BerriAI/litellm@v1.91.1...v1.91.1)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](BerriAI/litellm@0112e53).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.91.1/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- chore(release): backport [#&#8203;32256](BerriAI/litellm#32256), [#&#8203;32405](BerriAI/litellm#32405), [#&#8203;32524](BerriAI/litellm#32524) to stable/1.91.x and cut 1.91.1 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;32552](BerriAI/litellm#32552)

**Full Changelog**: <BerriAI/litellm@v1.91.0...v1.91.1>

### [`v1.91.1`](https://github.com/BerriAI/litellm/releases/tag/v1.91.1)

[Compare Source](BerriAI/litellm@v1.91.0...v1.91.1)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](BerriAI/litellm@0112e53).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.91.1/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- chore(release): backport [#&#8203;32256](BerriAI/litellm#32256), [#&#8203;32405](BerriAI/litellm#32405), [#&#8203;32524](BerriAI/litellm#32524) to stable/1.91.x and cut 1.91.1 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;32552](BerriAI/litellm#32552)

**Full Changelog**: <BerriAI/litellm@v1.91.0...v1.91.1>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/1475
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Jul 9, 2026
….1) (#488)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/berriai/litellm](https://images.chainguard.dev/directory/image/wolfi-base/overview) ([source](https://github.com/BerriAI/litellm)) | patch | `v1.91.0` → `v1.91.1` |

---

### Release Notes

<details>
<summary>BerriAI/litellm (ghcr.io/berriai/litellm)</summary>

### [`v1.91.1`](https://github.com/BerriAI/litellm/releases/tag/v1.91.1)

[Compare Source](BerriAI/litellm@v1.91.1...v1.91.1)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](BerriAI/litellm@0112e53).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.91.1/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- chore(release): backport [#&#8203;32256](BerriAI/litellm#32256), [#&#8203;32405](BerriAI/litellm#32405), [#&#8203;32524](BerriAI/litellm#32524) to stable/1.91.x and cut 1.91.1 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;32552](BerriAI/litellm#32552)

**Full Changelog**: <BerriAI/litellm@v1.91.0...v1.91.1>

### [`v1.91.1`](https://github.com/BerriAI/litellm/releases/tag/v1.91.1)

[Compare Source](BerriAI/litellm@v1.91.0...v1.91.1)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](BerriAI/litellm@0112e53).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.91.1/cosign.pub \
  ghcr.io/berriai/litellm:v1.91.1
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- chore(release): backport [#&#8203;32256](BerriAI/litellm#32256), [#&#8203;32405](BerriAI/litellm#32405), [#&#8203;32524](BerriAI/litellm#32524) to stable/1.91.x and cut 1.91.1 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;32552](BerriAI/litellm#32552)

**Full Changelog**: <BerriAI/litellm@v1.91.0...v1.91.1>

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNTIuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI1Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/488
stvnksslr pushed a commit to stvnksslr/litellm that referenced this pull request Jul 14, 2026
…expansion

fix(proxy): resolve os.environ/ refs for all AWS auth params in DB-sourced models

(cherry picked from commit 7d13f03)
edelauna pushed a commit to edelauna/litellm that referenced this pull request Jul 22, 2026
Root cause: PR BerriAI#30867 removed request-time os.environ/ expansion in
BaseAWSLLM.get_credentials. That is only safe if config-load pre-resolves
os.environ/ refs so the value reaching get_credentials is already the real
secret. The YAML config path has always done this. The DB-load path
(ProxyConfig._resolve_db_litellm_param) only re-expanded keys in a hardcoded
whitelist (_DB_LITELLM_PARAM_ENV_REF_KEYS) plus short-circuited env-ref
resolution entirely for team-scoped rows. PR BerriAI#32256 extended that whitelist
to 18 keys to unblock a customer whose Bedrock model with aws_role_name:
os.environ/BEDROCK_ASSUME_ROLE_ARN broke on v1.90+, but the whitelist is
structurally fragile: every future auth field breaks the same way until
someone remembers to add it

Fix: remove the whitelist and the team-scope short-circuit. The DB-load
resolver now expands os.environ/ on every string field, matching the YAML
path. Trust boundary stays on the write side: only PROXY_ADMIN can create
team_id=None rows, only team admins of a team can create rows scoped to
that team, and the request-body vector is still blocked by
_BANNED_REQUEST_BODY_PARAMS. Team-scoped rows now resolve env refs — this
is a deliberate LIT-3831 threat-model expansion trusting team admins for
env-var reads

Regression tests in tests/test_litellm/proxy/proxy_server/test_proxy_config.py:
- test_ProxyConfig__add_deployment_resolves_env_refs_after_db_decrypt pins
  admin-scoped rows resolve every field (previously api_base stayed literal)
- test_ProxyConfig__add_deployment_resolves_team_env_refs pins team rows
  resolve env refs (previously stayed literal)
- test_ProxyConfig__add_deployment_resolves_env_refs_on_arbitrary_field pins
  the no-whitelist invariant against a made-up field name
- test_ProxyConfig__add_deployment_resolves_env_refs_for_aws_bedrock_auth_params
  (from BerriAI#32256) still passes
- Path B counterparts (decrypt_model_list_from_db) mirror the above

Left as followups (not fixed here):
- /model/info and /v2/model/info still echo resolved values for fields not
  in the current pop-list (aws_role_name, aws_sts_endpoint, api_base, etc.).
  Fix is to extend remove_sensitive_info_from_deployment; separate PR
- Master-key rotation reads DB rows via decrypt_model_list_from_db which
  now resolves universally, so rotation collapses env-refs into hardcoded
  values. Pre-existing bug for the 6 previously-whitelisted fields; wider
  surface after this PR. Separate PR
yuneng-berri pushed a commit that referenced this pull request Aug 8, 2026
Root cause: PR #30867 removed request-time os.environ/ expansion in
BaseAWSLLM.get_credentials. That is only safe if config-load pre-resolves
os.environ/ refs so the value reaching get_credentials is already the real
secret. The YAML config path has always done this. The DB-load path
(ProxyConfig._resolve_db_litellm_param) only re-expanded keys in a hardcoded
whitelist (_DB_LITELLM_PARAM_ENV_REF_KEYS) plus short-circuited env-ref
resolution entirely for team-scoped rows. PR #32256 extended that whitelist
to 18 keys to unblock a customer whose Bedrock model with aws_role_name:
os.environ/BEDROCK_ASSUME_ROLE_ARN broke on v1.90+, but the whitelist is
structurally fragile: every future auth field breaks the same way until
someone remembers to add it

Fix: remove the whitelist and the team-scope short-circuit. The DB-load
resolver now expands os.environ/ on every string field, matching the YAML
path. Trust boundary stays on the write side: only PROXY_ADMIN can create
team_id=None rows, only team admins of a team can create rows scoped to
that team, and the request-body vector is still blocked by
_BANNED_REQUEST_BODY_PARAMS. Team-scoped rows now resolve env refs — this
is a deliberate LIT-3831 threat-model expansion trusting team admins for
env-var reads

Regression tests in tests/test_litellm/proxy/proxy_server/test_proxy_config.py:
- test_ProxyConfig__add_deployment_resolves_env_refs_after_db_decrypt pins
  admin-scoped rows resolve every field (previously api_base stayed literal)
- test_ProxyConfig__add_deployment_resolves_team_env_refs pins team rows
  resolve env refs (previously stayed literal)
- test_ProxyConfig__add_deployment_resolves_env_refs_on_arbitrary_field pins
  the no-whitelist invariant against a made-up field name
- test_ProxyConfig__add_deployment_resolves_env_refs_for_aws_bedrock_auth_params
  (from #32256) still passes
- Path B counterparts (decrypt_model_list_from_db) mirror the above

Left as followups (not fixed here):
- /model/info and /v2/model/info still echo resolved values for fields not
  in the current pop-list (aws_role_name, aws_sts_endpoint, api_base, etc.).
  Fix is to extend remove_sensitive_info_from_deployment; separate PR
- Master-key rotation reads DB rows via decrypt_model_list_from_db which
  now resolves universally, so rotation collapses env-refs into hardcoded
  values. Pre-existing bug for the 6 previously-whitelisted fields; wider
  surface after this PR. Separate PR

(cherry picked from commit 5862be3)
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.

3 participants