Activity Records - Security
2 min read
An audit trail must be trustworthy in two ways: records cannot be changed, and only users with permission can read them.
Records Cannot Be Changed
The database blocks changes. It rejects changing or deleting a record, for every user, the service included.
There is no API to change or delete a record.
The same event is saved once, even when it is sent again.
A database administrator could still turn off the block, or empty the table. That is why it runs on its own server, with its own small group of administrators.
Who Can Read
Only a signed-in user on the Admin page. There is no API key access.
Only with the Zitadel role
activity.records.read. Admin roles do not include it.Gatekeeper also checks the user, if your platform runs it.
Only their own company. The company comes from the API gateway, not from the request.
A user with the role sees all records of their company, including the input and output of every tool call. These can hold confidential content, like a search query or a document excerpt. Give the role only to the people who need it. Zitadel logs every role change.
Who Can Write
Events come in only through the RabbitMQ queue unique.activity-records.ingest. Intake trusts that queue: it takes the company and the actor from the event. Anyone who can publish to this queue can write records for any company, so only platform services may have access to it.
What Is Stored
Data | Stored | Shown in Admin |
|---|---|---|
Time of the action | Yes | Yes |
Source, for example MCP Hub | Yes | Yes |
Action, for example a tool call, and its details, for example the tool name | Yes | Yes |
Target: what the action was done on, for example an MCP server | When there is one | Yes |
Agent: the space the action ran in | When there is one | Yes |
User id and name | Yes | Yes |
IP address | When the sender knows it | Yes |
Yes | No | |
External id (from your own directory) | Yes | No |
Critical data: for a tool call, the tool's input and output | Yes | Under View raw JSON |
Critical data is the extra data of an action. For a tool call, it is the tool's input and output, so it can hold confidential content, like a search query or a document excerpt. It is stored as sent, without filtering, and capped at 1 MiB per event.
Names are saved with the record and are not updated later. For now, records are kept forever.
Redis also holds waiting events, critical data included, and a cache of user names, emails and external ids.
Checklist
9 294349681fdc incomplete PostgreSQL has private access only 10 b9dc5eb4f163 incomplete Only platform services can publish tounique.activity-records.ingest
11
360336facf99
incomplete
Redis has a password
12
41c8fe48cbe9
incomplete
activity.records.read given to named users only
13
007f61a9b4ee
incomplete
The critical data is acceptable to store for the sources you turn on