fix: prevent Anthropic token leaking to third-party anthropic_messages providers (salvage #2383) (#2389)
* fix: prevent Anthropic token fallback leaking to third-party anthropic_messages providers When provider is minimax/alibaba/etc and MINIMAX_API_KEY is not set, the code fell back to resolve_anthropic_token() sending Anthropic OAuth credentials to third-party endpoints, causing 401 errors. Now only provider=="anthropic" triggers the fallback. Generalizes the Alibaba-specific guard from #1739 to all non-Anthropic providers. * fix: set provider='anthropic' in credential refresh tests Follow-up for cherry-picked PR #2383 — existing tests didn't set agent.provider, which the new guard requires to allow Anthropic token refresh. --------- Co-authored-by: 0xbyt4 <35742124+0xbyt4@users.noreply.github.com>
This commit is contained in:
parent
f9fa7421cb
commit
525caadd8c
2 changed files with 12 additions and 8 deletions
17
run_agent.py
17
run_agent.py
|
|
@ -681,10 +681,11 @@ class AIAgent:
|
||||||
|
|
||||||
if self.api_mode == "anthropic_messages":
|
if self.api_mode == "anthropic_messages":
|
||||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token
|
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token
|
||||||
# Alibaba/DashScope use their own API key; do not fall back to ANTHROPIC_TOKEN (Fixes #1739 401).
|
# Only fall back to ANTHROPIC_TOKEN when the provider is actually Anthropic.
|
||||||
_base = (base_url or "").lower()
|
# Other anthropic_messages providers (MiniMax, Alibaba, etc.) must use their own API key.
|
||||||
_is_alibaba_dashscope = (self.provider == "alibaba") or ("dashscope" in _base) or ("aliyuncs" in _base)
|
# Falling back would send Anthropic credentials to third-party endpoints (Fixes #1739, #minimax-401).
|
||||||
effective_key = (api_key or "") if _is_alibaba_dashscope else (api_key or resolve_anthropic_token() or "")
|
_is_native_anthropic = self.provider == "anthropic"
|
||||||
|
effective_key = (api_key or resolve_anthropic_token() or "") if _is_native_anthropic else (api_key or "")
|
||||||
self.api_key = effective_key
|
self.api_key = effective_key
|
||||||
self._anthropic_api_key = effective_key
|
self._anthropic_api_key = effective_key
|
||||||
self._anthropic_base_url = base_url
|
self._anthropic_base_url = base_url
|
||||||
|
|
@ -3340,9 +3341,9 @@ class AIAgent:
|
||||||
def _try_refresh_anthropic_client_credentials(self) -> bool:
|
def _try_refresh_anthropic_client_credentials(self) -> bool:
|
||||||
if self.api_mode != "anthropic_messages" or not hasattr(self, "_anthropic_api_key"):
|
if self.api_mode != "anthropic_messages" or not hasattr(self, "_anthropic_api_key"):
|
||||||
return False
|
return False
|
||||||
# Alibaba/DashScope use their own API key; do not refresh from ANTHROPIC_TOKEN (Fixes #1739 401).
|
# Only refresh credentials for the native Anthropic provider.
|
||||||
_base = (getattr(self, "_anthropic_base_url", None) or "").lower()
|
# Other anthropic_messages providers (MiniMax, Alibaba, etc.) use their own keys.
|
||||||
if (self.provider == "alibaba") or ("dashscope" in _base) or ("aliyuncs" in _base):
|
if self.provider != "anthropic":
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -3768,7 +3769,7 @@ class AIAgent:
|
||||||
if fb_api_mode == "anthropic_messages":
|
if fb_api_mode == "anthropic_messages":
|
||||||
# Build native Anthropic client instead of using OpenAI client
|
# Build native Anthropic client instead of using OpenAI client
|
||||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token
|
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token
|
||||||
effective_key = fb_client.api_key or resolve_anthropic_token() or ""
|
effective_key = (fb_client.api_key or resolve_anthropic_token() or "") if fb_provider == "anthropic" else (fb_client.api_key or "")
|
||||||
self._anthropic_api_key = effective_key
|
self._anthropic_api_key = effective_key
|
||||||
self._anthropic_base_url = getattr(fb_client, "base_url", None)
|
self._anthropic_base_url = getattr(fb_client, "base_url", None)
|
||||||
self._anthropic_client = build_anthropic_client(effective_key, self._anthropic_base_url)
|
self._anthropic_client = build_anthropic_client(effective_key, self._anthropic_base_url)
|
||||||
|
|
|
||||||
|
|
@ -2413,6 +2413,7 @@ class TestAnthropicCredentialRefresh:
|
||||||
agent._anthropic_client = old_client
|
agent._anthropic_client = old_client
|
||||||
agent._anthropic_api_key = "sk-ant-oat01-stale-token"
|
agent._anthropic_api_key = "sk-ant-oat01-stale-token"
|
||||||
agent._anthropic_base_url = "https://api.anthropic.com"
|
agent._anthropic_base_url = "https://api.anthropic.com"
|
||||||
|
agent.provider = "anthropic"
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-oat01-fresh-token"),
|
patch("agent.anthropic_adapter.resolve_anthropic_token", return_value="sk-ant-oat01-fresh-token"),
|
||||||
|
|
@ -2908,6 +2909,7 @@ class TestOAuthFlagAfterCredentialRefresh:
|
||||||
def test_oauth_flag_updates_api_key_to_oauth(self, agent):
|
def test_oauth_flag_updates_api_key_to_oauth(self, agent):
|
||||||
"""Refreshing from API key to OAuth token must set flag to True."""
|
"""Refreshing from API key to OAuth token must set flag to True."""
|
||||||
agent.api_mode = "anthropic_messages"
|
agent.api_mode = "anthropic_messages"
|
||||||
|
agent.provider = "anthropic"
|
||||||
agent._anthropic_api_key = "sk-ant-api-old"
|
agent._anthropic_api_key = "sk-ant-api-old"
|
||||||
agent._anthropic_client = MagicMock()
|
agent._anthropic_client = MagicMock()
|
||||||
agent._is_anthropic_oauth = False
|
agent._is_anthropic_oauth = False
|
||||||
|
|
@ -2926,6 +2928,7 @@ class TestOAuthFlagAfterCredentialRefresh:
|
||||||
def test_oauth_flag_updates_oauth_to_api_key(self, agent):
|
def test_oauth_flag_updates_oauth_to_api_key(self, agent):
|
||||||
"""Refreshing from OAuth to API key must set flag to False."""
|
"""Refreshing from OAuth to API key must set flag to False."""
|
||||||
agent.api_mode = "anthropic_messages"
|
agent.api_mode = "anthropic_messages"
|
||||||
|
agent.provider = "anthropic"
|
||||||
agent._anthropic_api_key = "sk-ant-setup-old"
|
agent._anthropic_api_key = "sk-ant-setup-old"
|
||||||
agent._anthropic_client = MagicMock()
|
agent._anthropic_client = MagicMock()
|
||||||
agent._is_anthropic_oauth = True
|
agent._is_anthropic_oauth = True
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue