Security and cost audit for your AI agent toolchain — MCP servers, hooks and skills.
perimeter audit
Zero runtime dependencies · Works offline · Open-core (MIT)
Teams are wiring AI agents to MCP servers, Claude Code hooks, Cursor rules and Codex skills faster than they can secure or afford them. By default that means:
- Tool poisoning — malicious instructions tucked inside a tool description that the agent blindly obeys.
- Dangerous capability — a server that can run shell, write files, read credentials, or move money.
- Context bloat — several large servers can eat 30k+ tokens before the agent does anything useful.
- Silent drift — a tool changes since you last looked, and nobody notices.
One command answers three questions at once:
- Risk — what can each server, tool, hook and skill actually do?
- Cost — how much context and money do they burn per load?
- Change — did a tool quietly change since I last audited?
perimeter audit # human-readable verdict + findings
perimeter audit --enforce # gate CI (exit 1 on a finding)
perimeter audit --json # machine-readable
perimeter baseline # record a signature hash for drift
perimeter cost # token/cost footprint only
perimeter session # observe what agents actually ran
perimeter guard --server "npx -y @modelcontextprotocol/server-filesystem"
perimeter serve # preview the generated report
perimeter server # self-hosted fleet dashboard (Pro)
perimeter push <url> # send an audit to a Perimeter server| Risk | Perimeter | Most MCP scanners | Enterprise gateways |
|---|---|---|---|
| MCP servers | ✅ | ✅ | ✅ |
| Claude Code hooks / settings | ✅ | ❌ | |
Cursor / Codex skills + AGENTS.md |
✅ | ❌ | |
| Token & cost footprint | ✅ | ❌ | |
| Baseline + drift detection | ✅ | ||
CI gate (--enforce) |
✅ | ||
| Local · offline · zero-dep | ✅ | some | ❌ |
npm install --global perimetercliRequires Node 18+. Works on macOS, Linux and Windows.
cd my-project
perimeter audit # scan from the current directory
perimeter baseline # record a baseline for drift detection
perimeter audit --enforce --fail-on highHere's what an audit of a risky setup looks like (real output):
Perimeter — agent toolchain audit
======================================
Scanned 3 servers · 1 context file
Verdict: �[33mHIGH�[0m
0 critical · 1 high · 2 medium · 3 low · 0 info
── Servers (3) ──
shell-helper �[33mMEDIUM�[0m 2 caps · 2,600 tok · .mcp.json
paybot �[33mHIGH�[0m 2 caps · 5,000 tok · .mcp.json
websearch �[36mLOW�[0m 1 caps · 2,100 tok · .mcp.json
── Findings (7) ──
[�[33mMEDIUM�[0m] RISK-FSWRITE · Filesystem write access
shell-helper (@modelcontextprotocol/server-filesystem) — The server can create or modify files. Ensure writes are confined to the project directory.
Fix: Pin the working directory; deny paths outside an allowlist.
[�[33mMEDIUM�[0m] SUP-CREDS-ENV · Secrets present in server config env
shell-helper (@modelcontextprotocol/server-filesystem) — Credential-like env vars are configured: API_TOKEN. They may be visible in version control.
Fix: Reference secrets from the runtime secret store; never commit them.
[�[36mLOW�[0m] SUP-UNPINNED · Unpinned package version
shell-helper (@modelcontextprotocol/server-filesystem) — The server is fetched at runtime (npx/uvx) without a pinned version or lockfile.
Fix: Pin an exact version or vendor the package into the lockfile.
[�[33mHIGH�[0m] RISK-PAYMENT · Payment / financial capability
paybot (@stripe/mcp) — The server can initiate transactions or alter balances. Unauthorised or prompt-injected calls can move money.
Fix: Require a human approval gate; scope keys to a read-only or sandboxed account.
[�[36mLOW�[0m] SUP-UNPINNED · Unpinned package version
paybot (@stripe/mcp) — The server is fetched at runtime (npx/uvx) without a pinned version or lockfile.
Fix: Pin an exact version or vendor the package into the lockfile.
[�[36mLOW�[0m] SUP-UNPINNED · Unpinned package version
websearch (@modelcontextprotocol/server-brave-search) — The server is fetched at runtime (npx/uvx) without a pinned version or lockfile.
Fix: Pin an exact version or vendor the package into the lockfile.
[�[33mHIGH�[0m] INJECT-002 · Suspicious instructions in agent context file
AGENTS.md — Embedded instruction phrasing detected in AGENTS.md. An agent reads this text every session, so it can redirect behaviour.
Fix: Review the file and remove embedded instruction phrasing; consider pinning or signing it.
── Cost ──
model claude-sonnet · ~9,700 tokens/load · $0.10/load
- INJECT-001 — tool poisoning / prompt injection in tool metadata
- INJECT-002 — suspicious instructions in
AGENTS.md/CLAUDE.md/skills - SECRET-LEAK — a credential-looking value in an agent context file
- HOOK — risky Claude Code hooks (arbitrary code on tool use / session start)
- RISK-SHELL / RISK-EXFIL / RISK-PAYMENT / RISK-CREDS / RISK-CLOUD
- RISK-FSWRITE — filesystem writes
- SUP-TYPOSQUAT — package names one edit from a well-known server
- SUP-UNVERIFIED / SUP-UNPINNED / SUP-CREDS-ENV — supply-chain concerns
- TOK-BLOAT — a server whose tool schemas eat too much context
- DRIFT-NEW / DRIFT-CHANGED — new or mutated servers vs. your baseline
perimeter session goes further: it reads your actual agent session logs and
reports what was really called (Bash ×3, Write ×1…), with exact token
spend when the log records it.
See a full example audit report — a deliberately risky toolchain (shell server, curl-piped hook, injected rules, credential-sniffing skill) audited to a CRITICAL verdict with remediation for every finding.
perimeter guard proxies a real MCP server and blocks risky tool calls at
runtime based on a fail-closed policy. Point your agent at Perimeter instead of
the server directly:
{
"mcpServers": {
"filesystem": {
"command": "perimeter",
"args": [
"guard",
"--server",
"npx -y @modelcontextprotocol/server-filesystem",
"--allow",
"Read,Glob,List"
]
}
}
}Every call is logged to .perimeter/guard.log.jsonl for review.
For a team, run a local dashboard and push audits to it — a self-hosted version of the Pro continuous-audit loop:
perimeter server --port 4173
perimeter audit --json | perimeter push http://localhost:4173 --project acmeOpen http://localhost:4173 to see verdicts, findings and cost for every project
you push.
permissions:
contents: read
security-events: write # needed for the SARIF upload step below
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install --global perimetercli
- run: perimeter baseline
- run: perimeter audit --enforce --fail-on high --out perimeter-report
- uses: actions/upload-artifact@v4
with: { path: perimeter-report/ }
# Optional: publish findings to GitHub code scanning
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: perimeter-report/audit.sarifPerimeter emits SARIF too, so findings land directly in GitHub code scanning.
perimeter initCreates .perimeter/config.json:
{
"failOn": "critical",
"model": "claude-sonnet",
"budget": 1,
"maxTokensPerServer": 5000,
"block": ["@modelcontextprotocol/server-everything"],
"allow": [],
"ignoredRules": []
}The CLI is free and MIT. Perimeter Pro adds team policy, hosted dashboards,
remote-server analysis and drift alerts — see PRICING.md and
docs/pro.md.
Read CONTRIBUTING.md, then:
npm install
npm testPart of the stealth-alpha toolkit — eight zero-dependency CLIs for release automation, agent security, and repo hygiene.