最新资讯
bloomberg.com Nvidia 加强东南亚芯片追踪以打击走私 thestack.technology 模型路由需求升温,Agent Router 推出开源替代方案 www.youtube.com Google DeepMind 的 Philipp Schmid:AI 同事需要具备的七个要素 unite.ai Cashfree 为 AI Agent 的托管结账加入 WebMCP 工具 dev.to 我们在 DolphinBench 上测试记忆检索:纯关键词搜索暴露了自身回归 dev.to 别再把 Agent 写成 while 循环,把它建模为状态机 analyticsindiamag.com 小语言模型可能重塑企业 AI 部署方式 bloomberg.com Rightmove 与 Scout24 借 AI 产品应对低迷房市并上调展望 stackoverflow.blog 欢迎来到芯片时代:半导体制造、AI 数据中心与芯片设计的未来 www.youtube.com AI Agent 总犯同样的错:CentralAgent AI 将记忆重构为经验系统 pub.towardsai.net Netflix 科学家建议重采样 LLM 评判:5 次仅将误差棒缩小 13% pub.towardsai.net Jev 作为 LLM 前的静默层:构建提示感知的模型路由器
多元动态
登录 注册
智能体 dev.to · @Rojaneer

让 API 密钥远离 AI Agent:面向 MCP Server 的凭证隔离模式

原文 我的收藏

文章指出,在 MCP server 配置中把 BILLING_API_KEY 等实时密钥写入 agent 的 env 是常见但危险的做法:agent 会依据外部文本在运行时决定行为,一旦遭遇 prompt injection、被投毒依赖或恶意工具返回值,攻击者只需读取 os.environ 即可获取密钥。作者主张将凭证从 agent 进程中剥离,采用独立的凭证模式来限制泄露后的影响范围。

AI推荐理由 文章针对 MCP server 配置中把 API key 直接放进 agent 环境变量这一常见做法,指出 prompt injection、被投毒依赖或恶意工具返回值都可能让攻击者通过读取环境变量拿到密钥,并提出凭证隔离模式。属于开发者可落地的安全实践,但正文片段只给出问题描述,未展示完整方案与验证结果,需保留其建议性质。

72

正文

If you've wired an MCP server into an agent, you've probably done something like this: { "mcpServers": { "billing": { "command": "npx", "args": ["billing-mcp"], "env": { "BILLING_API_KEY": "sk-live-..." } } } } Enter fullscreen mode Exit fullscreen mode It works. It's also handing your live billing key to the least trustworthy process in the system. The problem An agent is a program that decides what to do at runtime based on text it was given — some of which comes from the outside world (a webpage it read, a document it summarized, a tool result). That's the whole point, and it's also why the agent process is the wrong place to keep a secret. Two things go wrong with the config above: The credential lives in the agent's environment. If the agent is compromised — prompt injection, a poisoned dependency, a tool that returns a malicious payload — the attacker is now one os.environ read away from your billing key. The blast radius of "the agent did something dumb" includes "the agent's keys are gone." The agent can call everything, and you can't prove what it did. The MCP server exposes a set of tools; the agent can call any of them. When something goes wrong, your evidence is scattered across logs that the agent itself could have influenced. You can't fix this by making the agent more careful. The agent is the untrusted part. You fix it by moving the trust boundary. The pattern: put a gateway between the agent and the MCP server Instead of letting the agent talk to the MCP server directly, put a small trusted process — a gateway — in the middle: agent ──► gateway ──► MCP server (holds the (needs the credential) credential) Enter fullscreen mode Exit fullscreen mode The credential lives in the gateway's environment, not the agent's. The agent gets a short-lived token scoped to its current run, and a URL that only reaches the MCP server through the gateway. On each tool call, the gateway injects the real credential just before forwarding upstream, and strips it from anything it hands back. The agent is starved of credentials. It can make tool calls, but it never possesses the secret that authorizes them. Compromise the agent and you get a revocable, per-run token — not the billing key. This is more than a reverse proxy, because the gateway is a policy decision point. Since every call goes through it, it can also: enforce which tools each agent may call (default-deny), enforce read-only access where you want it, and record every call and every refusal in one place the agent can't rewrite. A worked example Here's the pattern implemented with Agenthof, an open-source (Apache-2.0, Go) governance gateway. The config is the useful part; the tool is just one way to run it. 1. Register the MCP server with the gateway — this is where the secret lives: tools: ticket-search: kind: mcp url: https://tickets.internal/mcp credential_source: static_env token_env: TICKETS_MCP_TOKEN Enter fullscreen mode Exit fullscreen mode TICKETS_MCP_TOKEN is read from the gateway's environment. The agent process never sees it. 2. Grant each agent only the tools it needs — default-deny: name: legacy-triage execution: fronted endpoint: https://legacy.internal/agents/triage tools: - resource: ticket-search mode: all # every tool ticket-search exposes - resource: billing-mcp tools: [get_invoice, list_invoices] # only these two of billing-mcp Enter fullscreen mode Exit fullscreen mode An agent gets access to a resource only if it's named here, and to the tools it names (or an explicit mode: all). Leaving the list off isn't "allow everything" — it's rejected at config load. Widest access is always something you typed on purpose, never something you got by omission. Want read-only? Say so, and the operator's classification decides what counts: tools: - resource: billing-mcp mode: read-only # only the tools billing-mcp is declared to expose read-only Enter fullscreen mode Exit fullscreen mode 3. For OAuth-protected servers, even the client secret stays out of the agent. The gateway's broker mints a token from your identity provider per call: tools: billing-mcp: kind: mcp url: https://billing.internal/mcp credential_source: static_env grant_type: client_credentials issuer: https://idp.example.com/ token_endpoint: https://idp.example.com/oauth2/token client_id_env: BILLING_MCP_CLIENT_ID client_secret_env: BILLING_MCP_CLIENT_SECRET scope: billing.read read_only_tools: [get_invoice, list_invoices] Enter fullscreen mode Exit fullscreen mode The client id and secret are read from the gateway's environment; the agent gets the minted access token's effects, never the token, and never the secret that mints it. 4. Because everything flows through one point, every tool call and every refusal lands in a hash-chained, tamper-evident audit ledger — so "what did this agent actually do?" has a single, ordered answer. What this does not do Being honest about the boundary is the whole point, so: This governs and audits. It does not contain the agent. A compromised agent process still runs on some host; if that host has no sandbox, the process can still do local damage or reach the network directly. Keeping credentials out of the agent shrinks the blast radius — it is not a jail. Containment is your sandbox's job; this is the keys and the CCTV, not the locked room. The ledger is tamper-evident, not tamper-proof. Hash-chaining means edits are detectable after the fact. It does not stop an attacker with enough privilege from rewriting history — it makes the rewrite show up. Those aren't weaknesses to paper over; they're where the boundary actually sits, and knowing that is how you deploy the pattern correctly (gateway on a trusted host, agent in a sandbox, ledger shipped somewhere append-only). The takeaway Regardless of which tool you use, the pattern is portable: Secrets live in a trusted gateway, never in the agent. The agent gets a scoped, revocable, per-run token. Default-deny tool access. An agent reaches a tool only because you named it, and read-only where read-only is enough. Log every call and refusal somewhere the agent can't edit. The agent stays the flexible, fallible thing it's supposed to be — and it stops being the thing that holds your keys. A working implementation of all of the above is at github.com/agenthof/agenthof. If you're doing this differently — a sidecar, a service mesh, provider-side scoping — I'd genuinely like to hear how it's holding up.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容