Repository navigation
fix(security): Anthropic credentials are not fully scrubbed when a custom ANTHROPIC_BASE_URL is configured - #598
Open
failsafesecurity wants to merge 1 commit into
Conversation
…stom ANTHROPIC_BASE_URL is configured
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security fix: Anthropic credentials are not fully scrubbed when a custom ANTHROPIC_BASE_URL is configured
Severity: HIGH (CVSS 7.1)
CWE: CWE-522
File:
s01_agent_loop/code.pyWhat this fixes
The defect is that Anthropic credentials are not fully scrubbed when a custom
ANTHROPIC_BASE_URLis configured. The Anthropic SDK automatically reads bothANTHROPIC_API_KEYandANTHROPIC_AUTH_TOKENfrom the environment and attaches whichever is present to outbound requests, so removing only one credential — or removing none at all — leaves the other available to be sent to the configured base URL.In the numbered chapters (
s01_agent_loop/code.py:48-53), code that switches to a custom base URL pops onlyANTHROPIC_AUTH_TOKENand leavesANTHROPIC_API_KEYintact, so the real Anthropic key still travels in theX-Api-Keyheader. The generated-agent templates inskills/agent-builder/scripts/init_agent.py(lines 34-39 and 94-99) andskills/agent-builder/references/minimal-agent.py:20perform no credential scrub at all, so a scaffolded agent can send either the real Anthropic key or the Claude Code OAuth token to whatever base URL is set.s01_agent_loop/code.py:48-53(identical in s02-s15, s17 and agents/*) callsload_dotenv(override=True), then insideif os.getenv("ANTHROPIC_BASE_URL"):executesos.environ.pop("ANTHROPIC_AUTH_TOKEN", None)and constructsAnthropic(base_url=os.getenv("ANTHROPIC_BASE_URL"))..env.example:2-3instructs users to setANTHROPIC_API_KEYand documents switching providers viaANTHROPIC_BASE_URL, so a user following the documentation has a real key in the environment when they point the client at a third-party endpoint. The SDK resolves credentials from bothANTHROPIC_API_KEY(headerX-Api-Keyvia_api_key_auth) andANTHROPIC_AUTH_TOKEN(headerAuthorization: Bearervia_bearer_auth);auth_headersreturns{**self._api_key_auth, **self._bearer_auth}, so both credentials are attached to requests to the configured base URL. In a capture against a server bound to that URL, the request toPOST /v1/messagescarried `x-api-key: [REDACTED] while the authorization header was absent, confirming the scrub removes only the OAuth token.skills/agent-builder/scripts/init_agent.py:89-99(level-0 template),:94-99and:96-99(level-1 template), and:34-39(level-0 TEMPLATE) build the client after a bareload_dotenv()withclient = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"), base_url=os.getenv("ANTHROPIC_BASE_URL"))and no conditional scrub.skills/agent-builder/references/minimal-agent.py:20uses the sameapi_key=os.getenv("ANTHROPIC_API_KEY")pattern. Passingapi_key=explicitly forces the SDK to attachX-Api-Key: [REDACTED] to every request regardless ofbase_url. WhenANTHROPIC_API_KEYis unset,os.getenvreturns None, the SDK's explicit-credential check (/app/.venv/lib/python3.12/site-packages/anthropic/_client.py:203-212) is False, and the SDK reads bothANTHROPIC_API_KEYandANTHROPIC_AUTH_TOKENfrom the environment;_bearer_auth(same file, lines 348-351) emitsAuthorization: Beareron every request to the configured base URL. A capture onPOST /v1/messagesshowedAuthorization: Bearer [REDACTED] (also reproduced withdummy-oauth-tokenandsk-ant-oat01-REALTOKENas dummy tokens). The chapters guard this explicitly (e.g.s01_agent_loop/code.py:50-51, andagents/s01_agent_loop.py:44-45), proving the authors treat the token as sensitive; the scaffold dropped that guard. Control: inserting the chapters'os.environ.pop("ANTHROPIC_AUTH_TOKEN", None)before client construction yieldsclient.auth_token=Noneand no request.ANTHROPIC_BASE_URLis read from the environment or a project.env, so a cloned or shared project directory can control the endpoint that receives the credential.Preconditions: Exploitation requires a real Anthropic credential (
ANTHROPIC_API_KEYorANTHROPIC_AUTH_TOKEN) plus a non-defaultANTHROPIC_BASE_URLpointing at a third-party endpoint, set in the environment or.envas the repository documentation instructs for alternative providers.The change
Added
os.environ.pop("ANTHROPIC_API_KEY", None)inside the existingif os.getenv("ANTHROPIC_BASE_URL"):block so that when a custom base URL is configured, bothANTHROPIC_AUTH_TOKENandANTHROPIC_API_KEYare scrubbed from the environment before the Anthropic client is constructed. This prevents the SDK from automatically attaching the real Anthropic API key to outbound requests sent to the custom base URL.Impact if unpatched
A real Anthropic API key or Claude Code OAuth token is exfiltrated to whatever endpoint is configured via
ANTHROPIC_BASE_URL, enabling credential theft, billing abuse, and unauthorized API use. Every agent created by the recommended scaffolder inherits the leak.Prepared by OpenClaw BountyBot. Finding surfaced by Failsafe Nexus (Pandora) and the patch adversarially reviewed by GLM. Please review carefully — automated patches are a starting point, not a guarantee.