Trust is a list of what we don't claim.
Security products lose trust when the brochure outruns the code. This page states what PyxGrant enforces, how to verify it yourself, and where the boundary is. This site's tests fail if its copy crosses that boundary.
Each block carries the hash of the one before it. Change a record and every later link breaks.
Enforced in this build
- When a check can't complete, the call is refused. Recent releases closed fail-open paths found in our own audit, each with a regression test. The changelog lists them.
- The model is never the enforcement point. PyxGrant decides before the call reaches the tool, the model, or the other agent.
- A held call needs a signed human decision. Nobody answering means it is refused, and an agent can't approve its own call unless you allow it.
- What runs is re-hashed against what was approved, so a swapped call is refused.
- Under the hardened profile, an agent can't rewrite its own MCP config or PyxGrant's policy. A pinned policy isn't replaced by an edit nobody approved.
- Under the hardened profile, high blast-radius actions are held or refused before they run.
- Every decision is written to a hash-chained log sealed with Ed25519, with no plaintext secret in it.
- A restricted or irreversible tool result on SSE is buffered until the verdict. A deny releases no bytes. Bytes that already left on another stream stay sent.
Not claimed
- Prompt injection is not solved. Scoring is pattern-based, so new phrasing can pass. Pinning, taint, the blast-radius gate, and a human hold sit behind it.
- No FIPS 140-3 validated module. Signing is software Ed25519. ML-DSA-65 is an opt-in build.
- No FedRAMP authorization.
- No shipped kernel hook. The endpoint guard decides what a kernel agent sends it, but that agent isn't part of this build. Kernel confinement of a wrapped server is Linux only.
- No high availability for the console. Each machine's gateway keeps deciding from its own policy without it. The console binds to loopback unless you pass
-allow-nonloopback. - A local signing key is not an independent witness. Under the hardened profile the seal must use an external KMS or HSM key. A key file or anchor directory on the same disk no longer counts.
- Hardened needs a host-plane watcher. If
security.host_heartbeat_fileis not set, production-check fails withhost-unwatched. - Not the only product in this space, and not a replacement for your EDR or IdP.
pyxgrant boundaries prints the product's full list of limits.
What reaches PyxGrant, and how.
PyxGrant can only decide what is routed to it. Each row says how a surface reaches it and what happens at the edges.
| Surface | How it reaches PyxGrant | Status |
|---|---|---|
| MCP tool calls | An inline proxy in front of each server, over stdio or HTTP | Enforced Refused calls never reach the server, and results are cleaned before the model sees them. A restricted or irreversible tool result on SSE is held until the verdict. |
| A coding agent's built-in shell and file tools | The Claude Code and Cursor hook | Enforced if installed Allow, ask, or deny before the tool runs. PostToolUse scans a document the agent just read for macros and injected text. An agent without the hook isn't seen. If Open Policy Agent is configured and unreachable, the hook records |
| Model API calls | The model proxy | Enforced if routed Budgets, rate limits, held models, the shared agency counter, and injection checks. Under the hardened profile an unpriced model is refused. A client pointed straight at the provider isn't seen. |
| Agent-to-agent calls | The A2A proxy | Enforced once configured With no A2A policy it only observes. The design-partner profile refuses to start that way. |
| Your own agents: LangGraph, CrewAI, Python | The decision service on loopback | Your code asks Enforced when your code asks first and honors the answer. |
| Agentic browsers | A loopback decision daemon | Your code asks The daemon decides and holds. The in-browser shim that calls it isn't part of this build. |
| Payments, plant controllers, voice agents | Domain decisions | Decides only PyxGrant approves, holds, or refuses. |
| Web destinations | An egress-capture forward proxy | Observed, or refused by class It sees the host, not the encrypted content, and can refuse shadow or imitation services. |
| Finding agents | Machine scans, plus Microsoft Graph, Okta, and Amazon Bedrock inventories | Observed
|
| Sensitive data in results and arguments | Pattern checks and a local semantic layer | Partial Known formats such as keys, cards, SSNs, and record numbers, plus sensitive meaning without keywords. Not everything is caught. |
| Calls that skip PyxGrant | Reconciliation against the provider's own audit export | Named afterwards Not blocked: an inline gateway can't stop a call that never reaches it. It names each one, if you supply the export. |
| Every file and syscall on the host | None | Not covered Your EDR keeps this job. |
You don't have to trust us to check the record.
1. Keep the key apart
Set audit.signing_key_path or supply the key from the environment, so whoever can read the log can't re-sign it. PyxGrant warns when the key sits beside the log.
2. Walk the chain
pyxgrant audit verify-all checks every record's link to the one before it and the Ed25519 seal over the chain head.
3. Check a receipt offline
pyxgrant receipt verify checks one decision against a published key bundle or JWKS, with no call to us.
What PyxGrant records, and what it doesn't.
Recorded
- The agent that acted, and the person it acted for
- Server, tool, decision, reasons, and findings
- Detected secrets and personal data as fingerprints, not plaintext
- Held calls, who decided them, and when
Never done
- Keystroke logging or screen recording
- Productivity scoring or ranking developers
- Emotion inference
- Training on customer data