Skip to content

fix(mcp): scope HF bearer token to HuggingFace endpoints only#323

Open
lockezhou18 wants to merge 1 commit into
huggingface:mainfrom
lockezhou18:fix/scope-hf-bearer-to-hf-endpoints
Open

fix(mcp): scope HF bearer token to HuggingFace endpoints only#323
lockezhou18 wants to merge 1 commit into
huggingface:mainfrom
lockezhou18:fix/scope-hf-bearer-to-hf-endpoints

Conversation

@lockezhou18

Copy link
Copy Markdown

Problem

ToolRouter.__init__ (agent/core/tools.py) injects Authorization: Bearer <hf_token> into the headers of every configured MCP server:

for name, server in mcp_servers.items():
    data = server.model_dump()
    if hf_token:
        data.setdefault("headers", {})["Authorization"] = f"Bearer {hf_token}"
    mcp_servers_payload[name] = data

Two issues:

  1. Credential leak — the user's HF token is sent to every MCP server they configure, including unrelated/third-party servers that have no business seeing it.
  2. Breaks auth-enforcing servers — a server that grants a default identity to unauthenticated localhost callers (e.g. a self-hosted data-gateway) instead receives an unrecognized hf_... bearer and rejects every tool call. In my setup a local gateway returned invalid_token: bearer token not recognized on all calls; removing the stray header let it fall back to its default localhost identity and work.

Fix

Only attach the HF bearer when the server URL is a HuggingFace endpoint, matched on the parsed hostname (huggingface.co or a subdomain such as router.huggingface.co) rather than a substring — so lookalike hosts like huggingface.co.evil.com don't match. Stdio servers (no URL) and all non-HF remotes now receive no Authorization header.

if hf_token and _is_hf_endpoint(data.get("url")):
    data.setdefault("headers", {})["Authorization"] = f"Bearer {hf_token}"

The default hf-mcp-server (https://huggingface.co/mcp?login) still receives the token unchanged.

Verification

_is_hf_endpoint behavior:

URL Header attached
https://huggingface.co/mcp?login yes
https://router.huggingface.co/v1 yes
http://127.0.0.1:8001/mcp no
https://huggingface.co.evil.com/mcp no
stdio server (no url) no

Confirmed end-to-end: with the default hf-mcp-server plus a local data-gateway MCP, tool calls to both succeed after the change (before, the data-gateway rejected every call with invalid_token).

🤖 Generated with Claude Code

ToolRouter injected `Authorization: Bearer <hf_token>` into the headers of
*every* configured MCP server. This leaks the user's HF token to unrelated
third-party MCP servers, and breaks auth-enforcing servers: a local
data-gateway that grants a default identity to unauthenticated localhost
callers instead receives an unrecognized `hf_...` token and rejects every
tool call with `invalid_token: bearer token not recognized`.

Only attach the HF bearer when the server URL is a HuggingFace endpoint,
matched via the parsed hostname (huggingface.co or a subdomain) so lookalike
hosts like `huggingface.co.evil.com` don't match. Stdio servers (no URL) and
all non-HF remotes now receive no Authorization header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant