Skip to main content

trifectaguard

Stop AI agents from leaking your data or acting for an attacker, whatever the injected instruction says.

An agent that can read untrusted content (web pages, issues, emails), read your private data, and send things out can be turned against you by one injected instruction (the "lethal trifecta"). Detectors try to spot the injection's wording and can be evaded. trifectaguard tracks what the session has read and where each tool call sends it, and asks or blocks before private data, credentials, money or access go somewhere an injection chose.

untrusted input  →  reads private data / credentials  →  sends it out   ✗ blocked
     (issue, web page, email)                (post, email, curl, fetch, PR)

Works as Claude Code hooks, as a proxy in front of any MCP server (Claude Desktop, Cursor, …), or as a Python library for your own agents (LangChain/LangGraph, OpenAI Agents SDK, plain loops).

Quick start

git clone https://github.com/Ekaansh-Jain/trifectaguard && cd trifectaguard
pip install ".[mcp]"          # Python 3.10+; the [mcp] extra is only needed for the proxy
trifectaguard scan                # read-only: what could an injection make your AI apps do?

trifectaguard scan reads the MCP configs of Claude Code, Claude Desktop, Cursor, Windsurf and VS Code and explains every risky combination:

Claude Code  (not protected)
  HIGH  An injected instruction could make the agent send your credentials out
        untrusted input: WebFetch, WebSearch  →  then reads credentials: Read, Bash  →  then sends via: WebFetch, Bash

It changes nothing, starts no servers, never opens credential files and never prints tokens from your configs. --json for tooling; it exits 1 when an unprotected high-risk combination exists, so it can gate CI.

Protect your agents

For Verified in
Claude Code hooks Claude Code, including Read, WebFetch, Bash, Write and every MCP server a real Claude Code session
MCP proxy any MCP app; local (stdio) and remote (HTTP/SSE) servers a real Claude Desktop chat
Python library LangChain/LangGraph, OpenAI Agents SDK, your own loop a live LangGraph agent

Start any of them in mode: monitor to see what it would stop before it stops anything, then trifectaguard suggest -c <config> proposes config (trusted sites, remembered approvals) that removes repeat prompts without weakening the rules.

Claude Code

cp hooks.example.yaml hooks.yaml          # list your MCP servers; starts in monitor mode
trifectaguard hooks-snippet -c hooks.yaml     # paste the output into ~/.claude/settings.json

The engine runs as UserPromptSubmit / PreToolUse / PostToolUse hooks. It sees your request (so addresses and links you typed are trusted), tracks the whole session across built-in tools and MCP servers, and asks through Claude Code's normal approval prompt. It only ever answers "ask" or "deny", never "allow", so it can't loosen your permission settings. Bash is classified from its text (commands that can send data out or hide what they do get the scrutiny); that can't be complete, so keep Claude Code's own Bash permissions on, and for strong guarantees on shell commands use Claude Code's /sandbox (OS-level network limits) alongside trifectaguard. With remember_approvals: project, a destination you approve in a project isn't asked again there.

Any MCP app (Claude Desktop, Cursor, …)

cp gateway.example.yaml gateway.yaml      # your servers + which repos are public/private
trifectaguard inspect -c gateway.yaml         # how every tool is classified

In the app's MCP config, replace your servers with one entry running trifectaguard run -c /abs/path/gateway.yaml. One gateway fronts all of them, so a web page read through one server and a file read through another are one flow. Risky calls ask the user through MCP elicitation where the app supports it, and are blocked otherwise. Works with mcp 1.26+ and 2.x.

Your own agent (Python)

from trifectaguard import Guard, ask_in_terminal
from langchain_core.tools import tool     # or the OpenAI Agents SDK's @function_tool

guard = Guard({"tools": {
    "read_inbox": {"reads": ["untrusted", "private"]},
    "send_email": {"writes": "external", "destination": ["to"]},
}}, on_ask=ask_in_terminal)               # default: anything needing approval is denied

guard.user_message(user_request)          # destinations the user typed are trusted

@tool
@guard.tool
def send_email(to: str, body: str) -> str:
    """Send an email."""
    ...

A refused call doesn't run; the tool returns a short explanation the model can relay (or raises Blocked with blocked="raise"). One Guard per conversation.

How it works

  • Labels. Tool results add labels to the session: untrusted (issues, web pages, chat), private (private repos, local files), secret (credentials).
  • Flow rules. Before a call that sends something: untrusted + credentials → outside is blocked; untrusted + private → public or outside asks; untrusted content steering writes to CI/shell/agent config, access changes or deletions asks.
  • Destination provenance. For a recipient, IBAN, URL or user, it checks where the value came from: your request or trusted data (fine) vs only untrusted content (an injection chose it: ask). Matching is by whole token, and anything the agent itself wrote after reading untrusted content stays untrusted.
  • DLP. A secret the session read can't leave, even base64/hex/URL-encoded, reversed or spaced out.
  • Rug-pull pins (proxy). Tool definitions are pinned; a changed one is quarantined until you re-pin.
  • Policies are small YAML files. Presets ship for GitHub, filesystem, fetch, Slack and Claude Code's built-in tools; unknown tools are treated as untrusted with an unknown destination.

Results

On AgentDojo v1.2.2 with a worst-case agent that obeys every injection it reads:

Attacker's goal Still succeeds with trifectaguard
steal data (299 attacks) 0.3%
hijack payments, access or contact (153) 0%
deletions (39) 0%
steer the agent among legitimate options (100) 60% (not what it controls)

About 31% of benign tasks need one approval (44% as an MCP proxy, which can't see your request). It passes an adaptive red-team suite written against its own rules (20/20). With live models, attacks succeeded 0/12 times per model on AgentDojo banking (7/12 and 6/12 unprotected) and 0/20 in a LangGraph agent (11/20 unprotected), and it blocked exfiltration in real Claude Code and Claude Desktop sessions. Prompt-injection detectors (including this repo's own) hid clean data on 39–74% of benign tasks. Method, disclosed post-hoc changes and every number: RESULTS.md.

Limits

  • It controls where data and access go, not which legitimate option an agent picks, what text it writes to a legitimate recipient, or its final answer.
  • Security depends on the policies being right; a misclassified tool is a hole. trifectaguard inspect and trifectaguard scan show what each tool is treated as.
  • Bash classification in Claude Code is pattern-based: pair it with Claude Code's /sandbox for shell commands.
  • GitHub repo visibility comes from your config, not the API.
  • The proxy forwards tools (not MCP resources or prompts).
  • Nobody outside this project has tried to break it yet: please do (SECURITY.md).

Other open-source guards for Claude Code, described from their own READMEs and source at the commit read (2026-09-28). Not measured side by side: this is how each is documented to work, not a benchmark.

Acts on Blocks or warns Session memory Notes from their docs/source
lasso-security/claude-hooks (8fbfd14) tool output (PostToolUse) warns only no ~96 regex patterns in 4 categories (instruction override, role-play, encoding, context manipulation)
dwarvesf/claude-guardrails (b3c3e15) tool calls (PreToolUse), prompts, output blocks (deny rules, command checks); output scan warns no mostly Claude Code permission deny rules for sensitive paths; its README notes Bash reads aren't covered by Read deny rules. Its output scanner reads a tool_output field; Claude Code's documented field is tool_response
slavaspitsyn/claude-code-security-hooks (c4f126a) tool calls (PreToolUse) blocks no per-command rules: credential path + network tool in the same command, read guards for credential directories, POST domain whitelist, canary files
trifectaguard tool calls and output, across the whole session asks or blocks yes labels what the session has read and checks where each call sends data and who chose the destination; also an MCP proxy and a Python library

The others judge each call or output on its own (patterns, paths, command shapes); trifectaguard judges a call by what the session has already read and where the call sends it. They are complementary: path deny rules and trifectaguard can run together.

Research and reproducing the results

This repo started as a prompt-injection lab: a leak-rate benchmark of models against documented 2026 agent attacks (mock MCP server, fake canary secret), and a benchmark of injection detectors on tool outputs, including a fine-tuned ModernBERT (scripts/, data/, results and corrections in RESULTS.md).

pip install ".[mcp]" agentdojo openai python-dotenv
cp .env.example .env                              # Groq / NVIDIA NIM / Gemini keys, for live-model runs only
python run_all_tests.py --no-llm                  # every test, no API calls
python eval/redteam/adaptive.py                   # attacks on trifectaguard's own rules
python eval/agentdojo/worst_case.py --hook        # AgentDojo, model-independent (~3 min)
python eval/agentdojo/report.py                   # tables
python run_pilot.py --all --runs 10               # original model leak-rate benchmark

Inside this checkout the package is also importable as src.gateway (python -m src.gateway …), which the research scripts use.

Repository layout

  • src/gateway/: the package (trifectaguard when installed): engine.py (labels + flow rules), rules.py (YAML policies), policies/ (presets), dlp.py, hook.py (Claude Code), gateway.py (MCP proxy), guard.py (library), scan.py, pins.py. proxy.py/policy.py are the original research proxy.
  • eval/: AgentDojo, red-team, live-agent, Claude Code and Claude Desktop checks.
  • tests/: unit and end-to-end tests.
  • src/servers/github_mock.py, attacks/, src/harness/, run_pilot.py: the research benchmark (sandbox server with a fake secret).

Ethics

The benchmarks measure the vulnerability of your own agent setup in a sandbox so a defense can block it. Attack payloads recreate the structure of public disclosures and target only fake in-repo secrets.

Metadata

Release files for trifectaguard 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trifectaguard 0.1.0
File Size Uploaded Provenance Actions
trifectaguard-0.1.0.tar.gz 65.5 kB Without provenance Details for trifectaguard-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for trifectaguard 0.1.0
File Interpreter ABI Platform Actions
trifectaguard-0.1.0-py3-none-any.whl Python 3 none any Details for trifectaguard-0.1.0-py3-none-any.whl

Total release size: 120.2 kB

Release files / trifectaguard-0.1.0.tar.gz

Download URL trifectaguard-0.1.0.tar.gz
Size 65.5 kB
Tags Source
SHA-256 checksum
How to use checksums
32c9c61d318f2604ab4683c033f024897314b8d3678d6889c21df72a391e4d8a
BLAKE2b-256 checksum
How to use checksums
0784f0df2b8cf95d9ebee04561b6da33d94689d6a1eba54d3ff6544822636d11
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.10

Release files / trifectaguard-0.1.0-py3-none-any.whl

Download URL trifectaguard-0.1.0-py3-none-any.whl
Size 54.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce6798dd898e16cdaa2056fb29166cf76317f5160e4b3c28a2d9275ea58c30b1
BLAKE2b-256 checksum
How to use checksums
1e5a05523a199d8a92535e857d6f986fd1a502dac529fa1ba58f0067417bf8c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.10

Security for trifectaguard 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page