AI 代理的凭据防火墙。
核心主张是结构性的,而非策略性的:代理接收的是占位令牌,而非真实的 API 密钥。真实的密钥仅跨越一个网络边界——在 wardn 代理内部,前往上游 API 的途中——并在响应返回代理之前被剥离。日志、环境、LLM 上下文窗口、临时文件以及 shell 历史中仅保留占位符。```text agent process OPENAI_KEY=wdn_placeholder_a1b2c3d4e5f6g7h8 (useless) agent logs Authorization: Bearer wdn_placeholder_a1b2... (useless) LLM context wdn_placeholder_a1b2c3d4e5f6g7h8 (useless) wardn proxy injects the real key in-flight, single seam (deleted on response) ~/.vibeguard/vault.enc AES-256-GCM(Argon2id(passphrase)) (encrypted at rest)
这是关键的安全声明,且目前能够抵御智能体受损、提示注入、日志窃取和技能外泄。阅读 [docs/THREAT-MODEL.md](https://github.com/rohansx/wardn/blob/main/docs/THREAT-MODEL.md) 以了解已覆盖和未覆盖范围的诚实划分——包括在何种层级下可实现更强的“主机受损不会泄露任何信息”这一声明。
保险库本身(静态加密,基于口令派生的密钥)是一个真实组件,也是防火墙可以在单台机器上运行的原因。即将推出的 [docs/HOSTED-TIER.md](https://github.com/rohansx/wardn/blob/main/docs/HOSTED-TIER.md) 层级还将在代理周围包裹一个机密计算飞地,即使 VPS 被完全入侵,也无法读取密钥。
[](https://crates.io/crates/wardn)
[](LICENSE)
## 问题所在
如今,每个 AI 智能体框架都将 API 密钥存储在环境变量或 `.env` 文件中。一个受损的智能体、恶意技能、商品级窃密软件或提示注入,只要从 LLM 日志中提取出 `Authorization: Bearer sk-...`,就能完全获得你的凭证。```
~/.env → OPENAI_KEY=sk-proj-real-key # plaintext, readable by anyone
agent context → "Use OPENAI_KEY=sk-proj-real-key" # leaked into LLM context window
agent logs → Authorization: Bearer sk-proj-... # sitting in log files
wardn 向代理程序提供一个无用的占位字符串,并从其能触及的每个表面移除真实密钥。真实密钥在网络层注入——单个接缝处——并在响应到达代理程序之前从中剥离。``` agent environment → OPENAI_KEY=wdn_placeholder_a1b2c3d4e5f6g7h8 (useless) wardn vault → OPENAI_KEY=sk-proj-real-key (encrypted at rest) upstream request → Authorization: Bearer sk-proj-real-key (network transit only) upstream response → ...real keys stripped, placeholders returned... (re-injected on the way back) agent logs → Authorization: Bearer wdn_placeholder_a1b2... (useless) LLM context window → wdn_placeholder_a1b2c3d4e5f6g7h8 (useless)
## 架构```mermaid
flowchart TB
subgraph Agent["AI Agent Process"]
A1["Agent Code"]
A2["ENV: OPENAI_KEY=wdn_placeholder_a1b2..."]
end
subgraph Wardn["wardn daemon · localhost:7777"]
direction TB
P["HTTP Proxy"]
MCP["MCP Server\n(stdio)"]
subgraph Pipeline["Request Pipeline"]
direction LR
S1["Identify\nAgent"] --> S2["Resolve\nPlaceholder"] --> S3["Check\nAuth"] --> S4["Rate\nLimit"] --> S5["Inject\nReal Key"]
end
subgraph ResponsePipeline["Response Pipeline"]
direction RL
R1["Strip Real\nKeys"] --> R2["Replace with\nPlaceholders"]
end
subgraph Vault["Encrypted Vault"]
V1["AES-256-GCM"]
V2["Argon2id KDF"]
V3["Placeholder Map\nper agent × credential"]
end
end
subgraph External["External APIs"]
E1["api.openai.com"]
E2["api.anthropic.com"]
E3["..."]
end
A1 -- "placeholder token\nin headers/body" --> P
A1 -. "MCP: get_credential_ref\nlist_credentials\ncheck_rate_limit" .-> MCP
MCP -. "placeholder token\n(never real keys)" .-> A1
P --> Pipeline
Pipeline --> External
External --> ResponsePipeline
ResponsePipeline -- "response with\nplaceholders only" --> A1
Pipeline <--> Vault
ResponsePipeline <--> Vault
style Agent fill:#1a1a2e,stroke:#e94560,color:#fff
style Wardn fill:#0f3460,stroke:#16213e,color:#fff
style Pipeline fill:#16213e,stroke:#e94560,color:#fff
style ResponsePipeline fill:#16213e,stroke:#e94560,color:#fff
style Vault fill:#1a1a2e,stroke:#00d2ff,color:#fff
style External fill:#0a0a0a,stroke:#533483,color:#fff
Agent sends request with placeholder in Authorization header │ ▼ ┌─────────────────────────┐ │ wardn proxy │ │ localhost:7777 │ │ │ │ 1. Identify agent │ │ 2. Resolve placeholder │ │ 3. Check authorization │ │ 4. Check rate limit │ │ 5. Inject real key │ │ 6. Forward request │ │ 7. Strip key from resp │ │ 8. Return to agent │ └─────────────────────────┘ │ ▼ External API (only place real key exists in transit)
## Demo
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/12823/1fa6109ffd855ec98c173c5edd2d7ee77f6b0c918a3cdecb1ea5fbfe8326161d.gif" alt="wardn demo" width="800">
</p>
## 信任级别(坦诚版)
| 层级 | 部署位置 | 保障内容 |
|---|---|---|
| **自托管(当前)** | 你的笔记本电脑、你的VPS、CI | 静态加密保险库、防火墙声明对抗代理。**不**防御主机上的root权限。 |
| **托管(即将推出)** | wardn管理或自带云 | 机密计算环境(Nitro / SEV-SNP) + 远程证明 + 加密到代理流程。真正实现'主机被攻破也不泄露任何信息'的声明。 |
自托管层级是当前的主力保障,现已发布。托管层级是严格升级路径:需要费用和运维复杂度,其设计见 [docs/HOSTED-TIER.md](https://github.com/rohansx/wardn/blob/main/docs/HOSTED-TIER.md)。以下是涵盖与未涵盖内容的完整坦诚清单:
👉 **[docs/THREAT-MODEL.md](https://github.com/rohansx/wardn/blob/main/docs/THREAT-MODEL.md)** — 涵盖/未涵盖表格,明确指出'任何软件保险库都无法消除主机被攻破的风险',以及升级路径。
## 安装```bash
# Prebuilt binary (Linux/macOS, amd64/arm64), checksum-verified
curl -sSf https://raw.githubusercontent.com/rohansx/wardn/main/install.sh | sh
# or from crates.io
cargo install wardn
# or Homebrew, once the tap is published (see Formula/wardn.rb)
brew install rohansx/wardn/wardn
wardn vault create wardn vault set OPENAI_KEY wardn vault set ANTHROPIC_KEY
wardn setup claude-code
就这样。Claude Code 现在使用 wardn 的 MCP 服务器来获取占位符令牌,而不是从你的环境中读取真实密钥。
### 接下来会发生什么
1. Claude Code 调用 `get_credential_ref` → 获取 `wdn_placeholder_a1b2...`(非真实密钥)
2. 代理通过 wardn 代理发送包含占位符的请求
3. 代理将占位符替换为真实密钥,转发给 API
4. 代理在返回响应前从代理处剥离真实密钥
真实密钥永远不会进入代理的内存、日志或 LLM 上下文窗口。
## 本地仪表盘
一旦守护进程启动(`wardn serve` 或由 `wardn run` 生成),在浏览器中打开 **http://127.0.0.1:7777/ui**。它是一个只读、仅限本地的视图,包含:
- **凭证** — 每个存储的凭证及其 ACL(允许的代理、允许的域、速率限制 + 预算徽章)。
- **最近活动** — 最近 50 个代理事件,包括方法、域、路径、状态、代理、request_id 和记录的成本(`request_completed`、`credential_injected`、`rate_limit`、`budget_exceeded`、`loop_detected`、`request_error`)。
- **预算** — 每个凭证的配置预算(最大值、已花费、剩余、窗口、模式),并带有进度条,当超过 50%/80% 时从警告变为错误。
每 2 秒自动轮询。没有变更端点 —— 离开仪表盘的唯一途径是 API 本身(`/api/summary`、`/api/credentials`、`/api/audit?limit=N`、`/api/budgets`)。```bash
# Static, anonymous, never sees real keys
curl http://127.0.0.1:7777/api/summary | jq
wardn vault get OPENAI_KEY
wardn vault list
wardn serve
wardn serve --mcp --agent my-agent
## CLI 参考
### Vault 管理```bash
wardn vault create # create encrypted vault
wardn vault set OPENAI_KEY # store credential (prompts for value, no echo)
wardn vault get OPENAI_KEY # get placeholder token (never the real value)
wardn vault get OPENAI_KEY --agent bot # get placeholder for specific agent
wardn vault list # list all credentials
wardn vault rotate OPENAI_KEY # rotate value, placeholders unchanged
wardn vault remove OPENAI_KEY # remove credential
# Custom vault path
wardn --vault /path/to/vault.enc vault list
wardn serve # HTTP proxy on 127.0.0.1:7777 wardn serve --host 0.0.0.0 --port 8080 # custom bind address wardn serve --config wardn.toml # load config with rate limits + ACLs wardn serve --mcp --agent my-agent # proxy + MCP server (stdio)
### Claude Code / Cursor 集成```bash
wardn setup claude-code # register wardn as MCP server in Claude Code
wardn setup cursor # register wardn as MCP server in Cursor