🛡️ Pluto AgentGuard
Your Claude Desktop / Cursor / VS Code MCP config may already let an AI agent call tools with no authentication, or ship a hardcoded API key. Check in 30 seconds.
30-Second Scan
pip install pluto-aguard
# macOS Claude Desktop:
aguard scan ~/Library/Application\ Support/Claude/
# Windows Claude Desktop:
aguard scan %APPDATA%\Claude\
# Cursor / any project with a local mcp.json:
aguard scan .
Real output from scanning a realistic (but fictional) claude_desktop_config.json built entirely from real MCP fields — no invented schema, see examples/claude_desktop_config.json:
🔍 Scanning ...
🟠 HIGH: Hardcoded secret in env var 'GITHUB_PERSONAL_ACCESS_TOKEN' on server 'github' (MCP01:2025)
🟠 HIGH: Insecure HTTP transport on MCP server 'internal-metrics' (MCP07:2025)
🟠 HIGH: No authentication configured for remote MCP server 'internal-metrics' (MCP07:2025)
🟠 HIGH: Hardcoded GitHub Token detected (MCP01:2025)
📊 Risk Score: 44.8/100 ██████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░
📋 Findings: 4 high
No cloud accounts, no API keys, nothing leaves your machine — it's static analysis of the config file, not a live connection to your MCP servers. False positive? See docs/suppressions.md.
There's More Than a Scanner
Once you've found a problem, the harder question is "did my fix actually help, and can I prove it to whoever signs off on shipping this agent?" That's what the rest of AgentGuard is for — the two commands below are the part no other MCP scanner does:
git clone https://github.com/arshan846/pluto-aguard.git && cd pluto-aguard
# See the risk score drop *before* you apply a fix
aguard whatif --config ./examples/insecure-agent-config.yaml
# Generate a launch-approval packet: findings + policy coverage + sign-off checklist
aguard evidence ./examples/ --config ./examples/insecure-agent-config.yaml \
--policy ./examples/agent-policy.yaml
Plus policy coverage linting (test), an OWASP-inspired control report (owasp), and drift detection (baseline) — see Commands below, or the interactive demo for all 7 in action.
| Capability | Scanners | AgentGuard |
|---|---|---|
| Detect secrets & misconfigs statically (no server execution) | 🟡 Varies | ✅ aguard scan |
| Policy coverage linting (22 named attack scenarios) | ❌ | ✅ aguard test |
| "What-if" risk impact before applying changes | ❌ | ✅ aguard whatif |
| OWASP-inspired control coverage (20 controls) | ❌ | ✅ aguard owasp |
| Launch readiness evidence packets | ❌ | ✅ aguard evidence |
| Baseline drift detection | ❌ | ✅ aguard baseline |
| Behavioral trace audit with approval model | ❌ | ✅ aguard monitor |
MCP security scanners are multiplying fast (Snyk agent-scan, Invariant guardrails, AgentSeal) and mostly stop at config detection or runtime analysis. AgentGuard's differentiator is the pair above — quantified risk delta before you change anything, and a packet to hand whoever approves the launch — not the scanning itself, which is table stakes.
Real-World Validation: 1,200 GitHub Configs
We scanned 1,200 real MCP configs from public GitHub repos (1,159 unique projects) using AgentGuard:
| Metric | Result |
|---|---|
| Configs scanned | 1,200 |
| Total findings | 2,891 |
| 🔴 CRITICAL | 0 |
| 🟠 HIGH | 189 |
| 🟡 MEDIUM | 169 |
| ℹ️ INFO | 2,533 |
| Repos with HIGH findings | 156 (13%) |
What we actually found:
- 189 remote MCP endpoints with no authentication configured
- 169 unencrypted HTTP on non-localhost transport
- Hardcoded secrets in a subset of configs
- 2,533 informational items (capability inventory — shell access, browser automation, etc.)
Important context: Capability-related findings (e.g., a server having shell tools) are reported as INFO for awareness only. Per the MCP specification, human-in-the-loop enforcement is strictly a client/host responsibility, not the server's. See full methodology and results.
GitHub Action
- name: Agent Security Gate
uses: arshan846/[email protected]
with:
path: '.'
max-risk: '50'
fail-on: 'high'
policy: 'agent-policy.yaml'
attack-pack: 'all'
sarif-output: 'results.sarif'
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
See docs/github-action-usage.md for full options.
Commands
| Command | What It Does | Maturity |
|---|---|---|
aguard scan |
Static analysis — secrets, misconfigs, unsafe AI code patterns | ✅ Stable |
aguard test |
Policy coverage linting — 22 named attack scenarios across 6 packs | ✅ Stable |
aguard owasp |
OWASP-inspired control coverage report (20 controls) | ✅ Stable |
aguard whatif |
Policy impact simulation — risk delta before applying changes | ✅ Stable |
aguard evidence |
Launch readiness packet with approval checklist | 🔶 Beta |
aguard baseline |
Security snapshot + drift comparison over time | 🔶 Beta |
aguard monitor |
Behavioral trace audit — replays tool calls against policy | 🔶 Beta |
aguard scan
Finds real issues in any AI project — no MCP configs needed. Detects eval/exec on LLM output, hardcoded secrets (18+ patterns), missing authentication on remote endpoints, Dockerfile misconfigs, unpinned AI deps, LangChain unsafe settings, system prompt leaks, and more.
$ aguard scan ./my-project/
🔴 CRITICAL: Unsafe execution of LLM output: eval() (MCP05:2025)
🟠 HIGH: Hardcoded OpenAI Key detected (MCP01:2025)
🟠 HIGH: .env file not in .gitignore (MCP01:2025)
🟡 MEDIUM: Unpinned AI dependencies (MCP04:2025)
📊 Risk Score: 100/100 ██████████████████████████████████████████████████
📋 Findings: 1 critical · 14 high · 3 medium
CI flags: --max-risk 50 / --fail-on high / --format sarif
False positive? Suppress it via a .aguard.yaml file or an inline # aguard-ignore comment — see docs/suppressions.md. Use --no-suppress to see every finding regardless of suppression rules.
Not every check applies to every config: transport/auth/secrets checks work on any real claude_desktop_config.json, but the permission-wildcard and tool-poisoning checks look for metadata (permissions, tools[].description) that only exists in AgentGuard's own extended schema or in gateway configs that add it themselves — see docs/config-schema.md for exactly what's standard vs. extended, and examples/claude_desktop_config.json for a scan of a real, unmodified config.
aguard test
Policy coverage linting, not adversarial testing: for each of 22 named attack scenarios, checks whether the tool it would invoke is in your policy's denied_tools or require_human_approval list. Reports what gets caught vs. what gets through. No LLM needed — nothing is executed and no prompt text is evaluated. A scenario's attack_prompt is documentation of the threat it represents, not an input this command interprets; two scenarios that name the same tool (e.g. execute) get the identical verdict regardless of how different the underlying attack is.
⚠️ This tests whether your policy document would block each attack — not whether your actual LLM agent would resist it. Real agent resistance requires runtime testing against a live agent (planned for v1.2).
6 attack packs: prompt-injection, data-exfiltration, permission-escalation, approval-bypass, tool-poisoning, context-manipulation.
$ aguard test --policy agent-policy.yaml --attack-pack all
✅ PASS PI-001 Direct instruction override execute Blocked
✅ PASS DE-001 File export of sensitive data file_write Blocked
❌ FAIL DE-004 SQL data dump sql_query NOT caught
📊 Results: 21 blocked · 1 missed · 22 total
Recommended fixes:
→ Add sql_query to require_human_approval
CI flag: --fail-on-miss exits with code 1 if any attacks succeed.
aguard owasp
Evaluates 20 controls mapped to an OWASP-inspired control framework. Control IDs use a project-defined MCP01–MCP10 taxonomy that draws on OWASP LLM Top 10 and the emerging OWASP Agentic AI initiative, with MCP-specific extensions the existing standards don't yet cover.
$ aguard owasp ./my-project/
❌ MCP01:2025 Token Mismanagement: 3 failed, 1 passed
✗ AGC-MCP01-001: No hardcoded secrets
✓ AGC-MCP01-002: No static long-lived tokens
✅ MCP07:2025 AuthN/AuthZ: 2 passed
✓ AGC-MCP07-001: Remote servers have auth
✓ AGC-MCP07-002: HTTPS transport
📊 Control Coverage: 9/10 risks
Controls: 8 passed · 6 failed · 6 not tested · 20 total
aguard whatif
Simulates policy changes and shows risk score impact before applying them. Output below is the real, reproducible result of running aguard whatif --config examples/insecure-agent-config.yaml:
$ aguard whatif --config examples/insecure-agent-config.yaml
Current Risk Score: 100/100
✅ Restrict SQL tool to SELECT-only queries → 56 (↓ 44%)
✅ Add human-in-the-loop for file operations → 97 (↓ 3%)
✅ Rotate API keys to ephemeral tokens → 82 (↓ 18%)
✅ Add rate limits (100 calls/minute) and timeout (5 min) → 57 (↓ 43%)
✅ Restrict outbound network access to allowlisted domains → 82 (↓ 18%)
✅ Convert from implicit-allow to explicit tool allowlist → 82 (↓ 18%)
✅ Run agent in sandboxed execution environment → 82 (↓ 18%)
💡 Apply all 7 → Risk drops to 5 (↓95%)
aguard evidence
Generates a launch readiness packet — risk summary, findings, tool permissions, policy coverage, required mitigations, and sign-off checklist. See examples/sample-launch-readiness.md.
aguard baseline
Save a security snapshot, compare later to detect drift.
aguard baseline create . # Save current state
aguard baseline compare . # What changed?
aguard baseline compare . --fail-on-drift # CI: fail if new findings
aguard monitor
Replays agent action traces against a declared policy. Detects denied tool calls, unauthorized access, permission escalation, and missing/expired approvals.
aguard monitor --trace-file traces.jsonl --policy policy.yaml
Accepts real OTel GenAI semantic-convention traces (gen_ai.tool.name, gen_ai.operation.name — what OpenLIT and OTel-native LangChain instrumentation actually emit), this project's own OTel-shaped format, or a flat simple {"tool_name": "X", "tool_args": {}} format. See docs/trace-ingestion.md and examples/otel-genai-traces.jsonl.
Approvals are single-use — one approval authorizes exactly one matching call, not every future call to that tool — and, when both sides carry a timestamp, an approval recorded after the action it's supposed to cover is flagged as a DRIFT-BACKDATED-APPROVAL. See docs/approval-semantics.md.
How It Fits
┌─────────────────────────────────────────────────────┐
│ LAYER 1: Content Guardrails (existing) │
│ Azure Content Safety · NeMo · Guardrails AI │
│ → Protects what LLMs SAY │
├─────────────────────────────────────────────────────┤
│ LAYER 2: Agent Security (Pluto AgentGuard) │
│ scan · test · owasp · whatif · evidence · baseline │
│ → Watches what agents DO │
└─────────────────────────────────────────────────────┘
Risk Scoring
See docs/risk-scoring.md for the full scoring methodology — formula, weights, examples, CI threshold guidance, and limitations.
OWASP-Inspired Control Matrix
See docs/owasp-control-matrix.md for the complete mapping of 20 controls. Control IDs draw on OWASP LLM Top 10 (LLM01–LLM10) and introduce MCP-specific extensions (MCP01–MCP10) for risks the existing standards don't yet cover.
Roadmap
- v0.1–v0.5 — Scanner, monitor, whatif, evidence, baseline, CI gates, SARIF, HTML reports
- v0.8 — Policy coverage testing (17 scenarios, 5 attack packs)
- v0.9 — OWASP-inspired control framework (20 controls, coverage reports)
- v0.9.1 — Context manipulation pack (context stuffing, multi-turn confusion, indirect injection, RAG poisoning), supply-chain manifest poisoning scenario
- v1.0 — Runtime proxy / tool-call firewall (observability on live tool calls without full red-team harness)
- v1.1 — Multi-framework adapters (LangChain, CrewAI, AutoGen).
aguard monitoralready ingests real OTel GenAI semantic-convention traces (see docs/trace-ingestion.md) — a framework-specific setup adapter is what remains. - v1.2 — Live agent testing (send adversarial inputs to running agents)
Project Structure
pluto-aguard/
├── src/pluto_aguard/
│ ├── cli.py # 7 CLI commands
│ ├── models.py # Finding, RiskScore, ControlResult, etc.
│ ├── scanners/ # MCP + AI config + permission scanners
│ ├── testing/ # 22 attack scenarios across 6 packs
│ ├── controls/ # 20 OWASP-aligned control definitions
│ ├── evidence/ # Launch readiness packet generator
│ ├── baseline/ # Snapshot + drift comparison
│ ├── monitor/ # Behavioral trace audit
│ ├── simulator/ # What-If policy simulation
│ ├── suppressions.py # .aguard.yaml + inline finding suppression
│ └── reports/ # HTML + SARIF output
├── examples/ # Demo project + configs + traces
├── docs/ # Risk scoring, OWASP matrix, suppressions, GitHub Action docs
├── tests/ # 174 tests
├── action.yml # GitHub Action
└── SECURITY.md
Contributing
See CONTRIBUTING.md for setup and guidelines.
License
Apache License 2.0 — see LICENSE.
No comments yet
Be the first to share your take.