diff --git a/litellm/secret_managers/main.py b/litellm/secret_managers/main.py index a560f5222b9..dfc54a00baa 100644 --- a/litellm/secret_managers/main.py +++ b/litellm/secret_managers/main.py @@ -255,10 +255,12 @@ def get_secret( # noqa: PLR0915 return oidc_token elif oidc_provider == "env_path": # Load token from a file path specified in an environment variable + # within an allowed credential directory. token_file_path = os.getenv(oidc_aud) if token_file_path is None: raise ValueError(f"Environment variable {oidc_aud} not found") - with open(token_file_path, "r") as f: + safe_path = _resolve_oidc_file_path(token_file_path) + with open(safe_path, "r") as f: oidc_token = f.read() return oidc_token else: diff --git a/tests/litellm_utils_tests/test_secret_manager.py b/tests/litellm_utils_tests/test_secret_manager.py index 0a2419d0bea..1e0dd3034fe 100644 --- a/tests/litellm_utils_tests/test_secret_manager.py +++ b/tests/litellm_utils_tests/test_secret_manager.py @@ -199,13 +199,14 @@ def test_oidc_file(monkeypatch): assert secret_val == secret_value -def test_oidc_env_path(): - # Create a temporary file - with tempfile.NamedTemporaryFile(mode="w+") as temp_file: +def test_oidc_env_path(monkeypatch): + # Create a temporary file inside a directory added to the allowlist. + with tempfile.TemporaryDirectory() as temp_dir: + monkeypatch.setenv("LITELLM_OIDC_ALLOWED_CREDENTIAL_DIRS", temp_dir) + temp_file_path = os.path.join(temp_dir, "token.txt") secret_value = "secret-" + uuid4().hex - temp_file.write(secret_value) - temp_file.flush() - temp_file_path = temp_file.name + with open(temp_file_path, "w") as temp_file: + temp_file.write(secret_value) # Create a unique environment variable name env_var_name = "OIDC_TEST_PATH_" + uuid4().hex @@ -223,6 +224,21 @@ def test_oidc_env_path(): del os.environ[env_var_name] +def test_oidc_env_path_rejects_paths_outside_allowed_dirs(monkeypatch): + with tempfile.TemporaryDirectory() as allowed_dir: + monkeypatch.setenv("LITELLM_OIDC_ALLOWED_CREDENTIAL_DIRS", allowed_dir) + with tempfile.NamedTemporaryFile(mode="w+") as temp_file: + temp_file.write("do-not-read") + temp_file.flush() + env_var_name = "OIDC_TEST_PATH_" + uuid4().hex + monkeypatch.setenv(env_var_name, temp_file.name) + + with pytest.raises( + ValueError, match="outside the allowed credential directories" + ): + get_secret(f"oidc/env_path/{env_var_name}") + + def test_google_secret_manager(): """ Test that we can get a secret from Google Secret Manager