promtact

Zero-trust tool control for AI agents

An AI agent can be talked into calling the wrong tool. This decides whether it does.

Agents read documents, tickets and web pages, and then act on them. Anything they read can carry an instruction. Promtact sits between the agent and the tools it can reach and decides, per call, whether the call happens - allow, hold for a person, or refuse - then writes that decision to a record your own administrators cannot quietly change.

The agent never holds your credentials. API keys and tokens stay with the gateway and are attached only after a call has been allowed, so an agent that is talked into something has nothing to leak and nothing to reuse. A refused call never causes a secret to be read at all.

Request an evaluation See the demonstration Technical claims

What this is for

The call is stopped, not reported

An agent that has read a poisoned document will do what the document says. The decision happens before the tool runs: the message is not sent, the record is not deleted, the payment is not made. A log that tells you afterwards is an incident report, not a control.

You can prove what happened

Every decision is hash-linked to the one before it, and the head of that chain is countersigned by a witness outside the machine. Someone with root on the server cannot remove a decision without the gap being visible. That is the difference between a log and evidence.

Nothing leaves your network

It runs where your agents run. There is no vendor endpoint, no telemetry, no account. A gateway that inspects tool calls sees documents, arguments and credentials - sending that to a supplier would build the exfiltration path it exists to prevent.

The agent does not have to be rewritten

It speaks the Model Context Protocol, so it goes in front of the tool servers you already run and the agent keeps calling them the way it always did. Adoption is a configuration change, which matters more than it sounds: a control that requires rebuilding the thing it protects does not get deployed.

Where the obligation comes from

The EU AI Act requires high-risk systems to keep automatic records over their lifetime (Article 12) and to remain under meaningful human oversight (Article 14). DORA requires demonstrable ICT risk controls over third-party components, and an agent calling tools through an MCP server is one. Both of those describe a record of what was decided and a point at which a person decides.

That is what this produces: the record, and the decision point. Whether a given deployment satisfies a given obligation is a question for your counsel and your auditor, and this page does not answer it.

Who runs it

Security teams
You are being asked to approve agents that can reach ticketing, mail, cloud APIs and customer data. This is the control that lets you say yes with a boundary rather than no, and the evidence to show what that boundary caught.
MDR and managed providers
Per-tenant policy and isolation, so one deployment serves a customer base without their decisions or records meeting. The approval queue is something an analyst works, not another dashboard nobody opens.
Vendors embedding it
Source-available, one binary, no service dependency. Run the witness yourself and hold your own signing key: the arrangement that removes us from your customers' trust argument entirely, with no code change.

Where it sits

An agent's tool call passes through Promtact, which decides and records it before the tool runs AI agent MCP client tool call Promtact gateway policy on the request inspection of the response session provenance audit record, hash-linked allow hold for a person refuse Tool / MCP server the call runs Approval queue a person decides Nothing happens and it is recorded audit head published to an external witness, and to your SIEM
The decision happens before the tool runs, not after. That places this service in the latency path of every tool call, which is a real cost and is stated rather than omitted.

What it does

Decides before the side effect

A tool call is evaluated against policy and either runs, waits for a person, or is refused. Detection that reports what an agent already did is a log, not a control.

It gates what passes through it. An agent with another route to the same data has a route this does not see.

Inspects what comes back

The answer is examined before the agent reads it: instructions smuggled in characters that render as nothing, image URLs carrying data outward, credential shapes. A poisoned response is withheld.

Prompt injection cannot be reliably detected, and this does not claim to. Detection is the smaller half.

Carries provenance forward

Content returned by a tool is untrusted by origin, whatever it contains. A session that read it has its next outward action held for a person - with no dependence on anything having been detected.

The mark expires, and only outward actions are affected. A control that holds everything is one somebody switches off.

Records so the operator is not exempt

Every decision is hash-linked to the one before it, and the chain head is published to a witness outside the host, which refuses a chain that got shorter or was rewritten.

Without that witness the chain detects accidental corruption only: anyone able to write to the database can recompute every hash.

What it looks like

$ promtactl audit trail --last 4

02:37:05  #270  allowed
          tool      list_documents
          because   tool "list_documents" matched the approved manifest

02:37:05  #271  allowed
          tool      read_document

02:37:05  #272  WITHHELD - a tool's answer was kept from the agent
          tool      read_document
          because   tool result contains characters that are invisible to a
                    reader but not to a model

02:37:05  #273  HELD - waiting for a person
          tool      send_message
          because   action reaches outward after this session read untrusted
                    content, so it needs a person

$ promtactl audit verify

Records      267
Hash-linked  267
Chain        intact - every record still hashes to the one before it
Witness      agrees at record 267
             The witness refuses a chain that has been shortened or
             rewritten, so an operator cannot quietly edit this record
             even with full access to this server and its database.

This is output from a running deployment, not a mock-up. The same information is in the console, and the same commands are in the repository.

In front of a server nobody here wrote

The demonstration above uses tool servers from this repository, which proves the mechanism and not the integration. This is the other half: the official Model Context Protocol reference server, unmodified, with the gateway in front of it and a policy approving exactly one of its twelve tools.

$ curl ... -d '{"method":"tools/list"}'

['echo', 'get-annotated-message', 'get-env', 'get-resource-links',
 'get-resource-reference', 'get-structured-content', 'get-sum',
 'get-tiny-image', 'gzip-file-as-resource', 'toggle-simulated-logging',
 'toggle-subscriber-updates', 'trigger-long-running-operation']

$ curl ... -d '{"method":"tools/call","params":{"name":"echo", ...}}'

{"result":{"content":[{"type":"text","text":"Echo: through the gateway"}]}}

$ curl ... -d '{"method":"tools/call","params":{"name":"get-env"}}'

{"error":{"code":403,"message":"blocked by policy",
  "reason":"tool \"get-env\" is not on the approved manifest"}}

The tool refused there is get-env, which returns the process environment. On a real host that is where database passwords and API keys live. The upstream offers it, the agent may ask for it, and the answer is no - with the refusal in the audit record and the agent never learning what it would have contained.

For providers embedding it

The agent never holds the credential

Upstream credentials stay with the gateway and are attached only after a call has been allowed. A refused call never causes a secret to be read at all, so a denied call cannot be used to find out which credentials exist. The audit record carries a fingerprint, never the value.

A tool that returns a credential in its own response is a different problem, and inspection is the smaller half of it.

Your witness, your key

The witness signs what it saw with a P-256 key, and receipts are checked offline against the public half by whoever holds it. Run the witness yourself and the vendor is no longer part of the trust argument. The scheme is identical either way; no code changes.

A receipt proves a third party saw this chain head at this time. It does not prove the contents of any record.

Not a service you send data to

Nothing leaves the deployment. There is no vendor endpoint, no telemetry home, no account to create. A gateway that inspects tool calls sees document contents, arguments and credential material - shipping that to a vendor builds the exfiltration path it exists to prevent.

Which also means there is no vendor dashboard, and support cannot see what happened unless you show it.

Per-tenant, for a customer base

Policy, identities and isolation per tenant, so one deployment serves many customers without their decisions or records meeting. Provisioning is an API, and identities can come from SCIM.

Physical separation per tenant is a deployment choice rather than the default, and the default is logical.

Deployment

Where it runs
In your environment, beside your agents. A gateway that inspects tool calls sees document contents, arguments and credential material; sending that to a vendor builds the exfiltration path it exists to prevent.
What it is
A single Go binary with the console embedded, plus PostgreSQL. Linux, a container image, or systemd.
Dependencies
Two, deliberately: a PostgreSQL driver and a SAML library.
Integration
MCP proxy, HTTP gateway, or a direct decision API. Findings stream to an existing SIEM.
Multi-tenant
Per-tenant policy and isolation, for providers running it across a customer base.

Why this cannot wait for the next budget round

Evidence is not retroactive. The record of what an agent was allowed to do is written when the call happens, or it does not exist. Deploy this in six months and the six months before it have no record - not a thin one, none. When somebody asks what the agent did in March, the honest answer is that nobody knows, and that answer is the same whether or not anything went wrong.

The exposure grows with every tool you connect. An agent with read access is a question of confidentiality. An agent that can send mail, close tickets, call an API or move money is a question of consequences, and the second kind is being connected right now, in most organisations, by teams who are being asked to move quickly.

The obligations are already written. The EU AI Act requires automatic records over a system's lifetime and meaningful human oversight; DORA requires demonstrable controls over third-party ICT components. Neither waits for the agent programme to mature. What they ask for is a record and a decision point, and both have to exist before the auditor asks, not after.

None of that is an argument for buying this specific thing today. It is an argument for having the record start today, from whoever you choose. A control added later cannot describe what already happened.

Talk to us

The useful first conversation is thirty minutes and technical: what your agents can reach today, which of those calls would be held, and what the record would look like afterwards. Bring an engineer.

What comes out of it is a written answer to three questions - which of your current tool calls would be allowed, held or refused; what an auditor would see six months later; and what it would take to run it in front of your own stack. That is useful whether or not you buy anything, and it is yours either way.

Evaluation, OEM, anything else
contact@promtact.com
Security reports
The same address, or a private advisory on GitHub, which keeps the thread closed until a fix exists. See the policy and security.txt.
Where we are
Promtact GmbH (in formation), Zurich, Switzerland

Independent assurance, stated plainly: there has been no third-party penetration test and no SOC 2 or ISO 27001 audit. This is version 0.5 of a product built by a small team, and pretending otherwise would be the first thing your due diligence caught. What exists instead is reproducible - the scans, the commands and the findings are published so you can run them yourself rather than take a report on faith. An independent test is the natural next step and something we would scope together with a first partner.

Verify rather than believe

Each claim in technical-claims.md carries the command that checks it and states its own limits. Where a control does not do something, that is written next to what it does.

The security scans are published as instructions rather than as results. verify-it-yourself.md gives four tools with pinned versions, the commands, and the numbers to expect - including why some findings are excluded rather than fixed. You get your own number, which is the only kind worth having.

security-findings.md lists what has been found and the commit that fixed it, including a defect a human read past during the same review that the tool then caught. A page reporting nothing would mean either perfect software or a search that stopped early.

The source is public. There is no exploit logic in it and nothing that attacks a target.