The problem: posting is how data leaves
We tend to think of writes as the risky actions: refunds, merges, deletes. But for an agent that has read sensitive data, the most direct way to leak it is to write it somewhere someone else can read. A chat message to the wrong channel is the quiet version of that. It is the usual way prompt injection gets data out. I had this hole myself. Recorded as G-76 on 2026-09-28: the first Slack policy approved a post when the agent declared two facts true, “the content is approved” and “the channel is authorized”. Nothing checked either. Worse, the connector posted to the channel named in the request’s parameters, and nothing compared that with the channel the decision was made about. An agent could name an allowed channel in one field and post to another.The idea: the channel is a server fact, and a person signs
Which channels an agent may post to is not something the agent should say. It is a setting the operator decides, outside the request. And each post should still have a person behind it.How Parmana does it
The Slack connector has one action,slack:post-message, governed by slack-post-message 1.1.0.
- The server keeps the list.
SlackChannelSignalVerifierrefuses a post unless the channel the message goes to is exactly the request’s target and is on the server’s allowlist,SLACK_ALLOWED_CHANNEL_IDS. It checks before the decision and again at release. If the list is unset or empty, every post is refused. - The connector checks too. The Slack adapter refuses, before any network call, a channel that is not the target. Naming one channel in the target and another in the parameters no longer works.
- A signed approval for the channel. Since 2026-09-30, a post is approved only with a signed approval from a trusted approver for that channel, used once. The agent’s “channel is authorized” claim is no longer trusted at all.
- The agent’s facts can only refuse. “Content approved” and “channel authorized” are still declared by the agent. If either is false the post stops; neither can approve it.
POST /execute show a post with an approval to a listed channel lands once. No approval, an approval
for another channel, a channel off the list, a mismatched channel in the parameters, and an unset list are each refused
with zero calls to Slack.
What it does not do
- The text is still the agent’s. An approval covers the channel, not the message. An approved post carries whatever the agent writes, only to a listed channel. If the operations channel itself is the wrong audience for borrower data, the allowlist will not save you. Approving the content would need the person to see the text before signing, which the current design does not require.
- Slack posting is not yet in use in Parmana’s production. The claims register lists its production use as future work. This connector has been run only in tests and tutorials, against a stand-in for Slack, never posting to a real workspace through Parmana.
- One person per post is a real cost. Every post needs a signed approval, single use. For a nightly summary that is one signature a night. For a chatty agent it is a person on call. Some teams will decide that is too slow, and they will be right for their case; Parmana does not offer an automatic path.
- One person approves. In Parmana’s own production one approver is trusted, and I hold that key.
- It does not stop a direct call. An agent that keeps its own Slack bot token can post without Parmana.