Require AGENT_MCP_TOKEN for non-loopback MCP binds#15
Merged
Conversation
The MCP server's only trust boundary was the bind address: flipping
AGENT_MCP_BIND from 127.0.0.1 to 0.0.0.0 silently exposed every tool —
allocate_ports, query_envoy_routes, agent_check_update --force — with
no per-request auth.
Changes:
- Add AGENT_MCP_TOKEN (--mcp-token) config option.
- serve_mcp refuses to start when the bind is non-loopback and no token
is configured. The rest of the agent keeps running; operator gets an
error! log and chooses to set the token or revert the bind.
- mcp_handler validates Authorization: Bearer <token> against the
configured token in constant time; returns 401 on missing/invalid.
- Setting the token on a loopback bind is allowed and stacks for
defence in depth.
- is_loopback_bind recognises 127.0.0.0/8, ::1, and `localhost`; treats
unparseable strings as non-loopback (fail-closed).
5 unit tests cover loopback detection (IPv4, IPv6, localhost,
wildcards, garbage) and the constant-time comparison helper.
Docs updated: sigma-agent README + CLAUDE.md, and docs/ai-triage.{en,zh}.md
security-model sections.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Closes the last gap from the AI-features review: the MCP server's only trust boundary was the bind address. Flipping
AGENT_MCP_BINDfrom127.0.0.1to0.0.0.0silently exposed every tool —allocate_ports,query_envoy_routes,agent_check_update --force— to anyone who could reach the agent, with no per-request auth.How the fix works
AGENT_MCP_BINDAGENT_MCP_TOKENserve_mcprefuses to start; louderror!log; agent keeps running with MCP disabledWhen a token is configured, every request must carry
Authorization: Bearer <token>. Comparison is constant-time (length-stable XOR loop). Missing/invalid → HTTP 401.Why "refuse to start" instead of "auto-generate a token"
Generating a token silently would still ship a secret out-of-band that the operator might not notice. Loud refusal forces the operator to make an explicit decision. The agent itself stays up — only MCP is disabled — so heartbeat / xDS / metrics keep working.
Loopback detection
is_loopback_bindrecognises:127.0.0.0/8(viaIpv4Addr::is_loopback)::1(handles[::1]:portbracket form)localhost(case-insensitive)Anything else —
0.0.0.0,::, public IPs, DNS names, unparseable strings — is treated as non-loopback (fail-closed).Tests (5 new, all passing)
```
running 5 tests
test mcp::tests::constant_time_eq_matches_string_eq ... ok
test mcp::tests::loopback_recognises_localhost ... ok
test mcp::tests::loopback_recognises_ipv4_127 ... ok
test mcp::tests::loopback_recognises_ipv6 ... ok
test mcp::tests::loopback_rejects_wildcards_and_externals ... ok
test result: ok. 5 passed; 0 failed
```
Docs
sigma-agent/README.md— new env-var row, expanded "Security defaults" section with a copy-paste example for off-loopback deployment.sigma-agent/CLAUDE.md— config table + MCP security contract updated.docs/ai-triage.{en,zh}.md— Component 1 (agent) security-model bullets updated.Test plan
cargo test --bin sigma-agent mcp::— 5/5 green locallyAGENT_MCP_ENABLED=true AGENT_MCP_BIND=0.0.0.0:9103(no token) → agent logs the refusal and continues; MCP port not boundAGENT_MCP_TOKEN=...→ MCP serves; request withoutAuthorizationreturns 401; request with correct token returns 200🤖 Generated with Claude Code