From a139fd4141a4e672e807c29de79821f865b8d3fa Mon Sep 17 00:00:00 2001 From: latent-9 <296084221+latent-9@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:20:42 +1200 Subject: [PATCH] fix(aws): stop ambient bearer credentials leaking under skip_auth AnthropicAWS passes auth_token=None to the parent constructor, which then falls back to ANTHROPIC_AUTH_TOKEN from the environment. With skip_auth=True the subclass suppressed its own SigV4 and x-api-key layers, but the parent's env fallback still installed a Bearer token, so requests carried an Authorization header that skip_auth promises will not exist, and the ambient credential leaked to whatever base URL the client targets. Add a _bearer_auth override symmetric with the existing _api_key_auth override: return no header while _skip_auth is set. test_skip_auth_no_auth_headers covers this; it only fails on machines where ANTHROPIC_AUTH_TOKEN is exported (for example Claude Code sessions), which is why CI never caught it. --- src/anthropic/lib/aws/_client.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/anthropic/lib/aws/_client.py b/src/anthropic/lib/aws/_client.py index 31d577124..009a195fe 100644 --- a/src/anthropic/lib/aws/_client.py +++ b/src/anthropic/lib/aws/_client.py @@ -136,6 +136,16 @@ def _api_key_auth(self) -> dict[str, str]: return {} return super()._api_key_auth + @property + @override + def _bearer_auth(self) -> dict[str, str]: + # skip_auth must also silence ambient bearer credentials: the parent + # constructor falls back to ANTHROPIC_AUTH_TOKEN from the environment, + # and a leaked Authorization header defeats the point of skip_auth. + if self._skip_auth: + return {} + return super()._bearer_auth + @override def _validate_headers(self, headers: httpx.Headers, omitted: frozenset[str]) -> None: if self._use_sigv4 or self._skip_auth: @@ -344,6 +354,16 @@ def _api_key_auth(self) -> dict[str, str]: return {} return super()._api_key_auth + @property + @override + def _bearer_auth(self) -> dict[str, str]: + # skip_auth must also silence ambient bearer credentials: the parent + # constructor falls back to ANTHROPIC_AUTH_TOKEN from the environment, + # and a leaked Authorization header defeats the point of skip_auth. + if self._skip_auth: + return {} + return super()._bearer_auth + @override def _validate_headers(self, headers: httpx.Headers, omitted: frozenset[str]) -> None: if self._use_sigv4 or self._skip_auth: