Skill Vetter
一个面向 Security 场景的 Agent 技能。原始说明:Security-first skill vetting for AI agents. Use before installing any skill from ClawdHub, GitHub, or other sources. Checks for red flags, permission scope, and suspicious patterns.
一个面向 Security 场景的 Agent 技能。原始说明:Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env fil...
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
A security skill that ensures API keys stay local and are never sent to Claude.
Activate whenever the user wants to:
.env, *.key, secrets.*, or any credentials file.sh, .bash, curl commands, config files) that may contain a hardcoded API key.env or key files directly — do not use bash cat .env or file read tools on any file containing keysread_file_masked insteadkey-guard MCP server for anything key-relatedThe key-guard MCP server exposes five tools:
list_keysDiscover all available key names — never values.
Call: list_keys()
Returns: { keys: ["KEY_A", "KEY_B", "KEY_C"] }
validate_keyCheck if a key is configured without seeing it.
Call: validate_key({ key_name: "OPENAI_API_KEY" })
Returns: { exists: true, length: 51, preview: "sk-a****", message: "Key is set" }
call_apiMake an authenticated HTTP request locally. The key is injected by the MCP server — Claude only sees the API response.
Call: call_api({
key_name: "OPENAI_API_KEY",
url: "https://api.openai.com/v1/models",
method: "GET"
})
Returns: { status: 200, data: { ... API response ... } }
read_file_maskedRead a script or config file with all key values replaced by {{KEY_NAME}} placeholders. Use this instead of reading files directly.
Call: read_file_masked({ file_path: "./call.sh" })
Returns: {
content: "curl -H 'Authorization: Bearer {{OPENAI_API_KEY}}' https://..."
}
You can now safely view and suggest edits to the non-key parts.
write_file_with_keysWrite a file back after editing, with {{KEY_NAME}} placeholders substituted with real key values locally.
Call: write_file_with_keys({
file_path: "./call.sh",
content: "curl -H 'Authorization: Bearer {{OPENAI_API_KEY}}' https://api.openai.com/v1/chat/completions ..."
})
Returns: { success: true, message: "File written with keys substituted locally" }
If the MCP server hasn't been registered yet:
# Clone the repo
git clone https://github.com/your-username/key-guard.git
# Copy .env.example to .env and fill in your keys
cp .env.example .env
# Register the MCP server (run once) — replace the path with your actual clone location
/mcp add key-guard node /path/to/key-guard/key-guard.js
# Or add directly to ~/.copilot/mcp-config.json for auto-load on restart:
# {
# "mcpServers": {
# "key-guard": {
# "command": "node",
# "args": ["/path/to/key-guard/key-guard.js"]
# }
# }
# }
1. Call validate_key({ key_name: "OPENAI_API_KEY" })
2. Report back: "Yes, your key is set (51 chars, starts with sk-a****)"
1. Call call_api({
key_name: "OPENAI_API_KEY",
url: "https://api.openai.com/v1/chat/completions",
method: "POST",
body: { model: "gpt-4o-mini", messages: [...] }
})
2. Use the returned response — never the key itself
Do NOT read .env directly.
Instead, call validate_key for each expected key name and show:
- Which keys are configured
- Approximate length (as a sanity check)
Never show actual values.
1. Call read_file_masked({ file_path: "./call.sh" })
→ Claude sees "curl -H 'Authorization: Bearer {{OPENAI_API_KEY}}' ..."
2. Make the requested edit to the non-key parts
3. Call write_file_with_keys({ file_path: "./call.sh", content: "<edited content with {{OPENAI_API_KEY}} still in place>" })
→ MCP substitutes the real key before writing to disk