Skip to content

Security model

The guarantees a Chickpea deployment enforces in code, the mechanism behind each one, and the boundaries it does not claim.

Updated View as Markdown

The Chickpea security model is the set of rules a deployment enforces in code rather than in a prompt. Where a prompt-level rule can be argued with by anything that reaches the model, these rules are read from stored state and re-checked at the moment of each use. This page states each guarantee, names the mechanism behind it, marks what it does not cover, and says how to report a vulnerability.

The guarantees

  • No ambient listening. In every channel, a top-level message that mentions no one is dropped before any model is involved. Unmentioned root messages never trigger classification, model spend, memory writes, or work.
  • Credentials never reach the model. Credentials never enter model context or the tool arguments the model writes. The model picks a connection by ID and the secret goes in at egress.
  • Conversation cannot expand authority. Authority comes from stored grants and saved instructions, read from stored state and re-checked at the moment of each use, never from anything produced during the turn. Message text, retrieved content, and tool output are data, never permission.
  • Consequential actions need confirmation. Minor reversible writes may proceed without confirmation. Consequential ones (sending a message or email, deleting, publishing, broad or bulk changes) require confirmation unless the saved Agent instructions explicitly authorize that class of action.
  • Per-Agent isolation. Connections, memory, skills, repositories, and reach all stop at the Agent. Nothing is reused across Agents implicitly.
  • Slack OIDC is the only human sign-in. No passwords. The first installer becomes the first Owner, bound to an exact workspace and user tuple.
  • An editor may publish only to a channel they belong to. Chickpea Admin status does not bypass Slack channel membership.
  • Self-hosted state. Runtime, model traffic, configuration, memory, and connector credentials stay in infrastructure you operate.
  • Memory is advisory, never policy. Live instructions, current permissions, and verified grant state win.
  • Minimal product telemetry. Six content-free, anonymous product events, with a complete operator opt-out.

Where authority comes from

Three stored things decide what an Agent may do on a turn: the channel grants that say where it may work, the saved Agent instructions that say what it may do without asking, and live Slack membership for the person who addressed it. None can be written by talking to the Agent.

A channel message that names no Agent handle never becomes a turn. It is ignored with the reason unaddressed_channel_message before any classification step, so there is no model call to bill.

When a turn does run, the saved Agent instructions are handed to the model inside a marked block, alongside a fixed statement that Slack conversation text, retrieved content, and tool output are untrusted task inputs that can never grant new authority. That statement is part of the request Chickpea builds, not something an Agent’s author can edit away.

Schedules run unattended, so they re-read every authority input immediately before each run. A schedule whose Agent was archived, whose creator lost their membership, or whose connection is gone fails with an explicit authority error instead of running on stale permission.

How credentials stay out of the model

The model never sees a secret because it never handles one. It selects a connection by ID, and Chickpea resolves the material at the moment of the call.

  • The account is re-checked, not trusted from the plan. Before returning any secret, Chickpea re-reads the connection account and the Agent’s binding, and confirms the acting member still resolves to the same live Slack identity in the same workspace.
  • The binding is a ceiling. An account’s capabilities are intersected with what the Agent was granted, so re-authorizing an account with wider scopes never widens the Agent.
  • The secret goes in at egress. Each connector gets its own network scope whose allow-list holds only that connector’s hosts, paths, and methods, with the credential attached as a header there. A redirect off a connector’s host cannot carry the credential anywhere else.
  • Anything not governed by a connection is narrower. The default network policy is an allowlist with no domains at all, and hosts an operator adds under Settings → Network policy are limited to GET, HEAD, and POST. Full internet reach is a deliberate open setting, not a default.
  • Private space is refused. Outbound requests reject private and loopback addresses. An MCP server URL must be https, may not embed credentials, and may not name localhost or a .local, .internal, or .localhost host, checked when it is saved and again at turn time.
  • Leaked-looking text is redacted on the way out. Slack tokens, sk-ant- and sk-proj- keys, GitHub tokens, AWS access key IDs, and PEM private keys are matched by shape and removed. The Slack streaming path holds a suspect tail back until redaction can no longer rewrite it.

Who may sign in and who may publish

Sign-in is a Slack OIDC flow requesting openid, profile, and email, with a browser-bound hashed state, a nonce, and the exact installed workspace. Every Admin request re-resolves the canonical workspace and user pair and requires an active Chickpea membership, so a valid Slack identity alone is not a session. Suspended, removed, mismatched-workspace, guest, and Slack Connect identities are denied.

Publishing an Agent to a channel takes two things at once: the right to edit that Agent, and membership of that channel. An Owner who is not in a private channel cannot publish an Agent into it.

What leaves your infrastructure

Model traffic goes to the provider you pinned, and connector traffic to the services you connected. Three other paths are worth naming in a review.

What Leaves your infrastructure Avoidable
Composio-managed connectors OAuth storage, refresh, and API execution for those accounts, if you opt in Yes. Native API and MCP connections keep their credentials with you.
The shared Slack gateway Encrypted installation credentials and sanitized health metadata. Not Slack message or event bodies, which it does not durably store. Yes. Pick “Use your own Slack app”, which talks directly to your deployment.
Product telemetry Six anonymous events carrying counts and coarse enums. No messages, prompts, tool data, IDs, names, or error text. Yes. Set DO_NOT_TRACK or CHICKPEA_DISABLE_TELEMETRY.

Why it works this way

The conversation is the one input an outsider can write to. A customer pastes text into a ticket, a retrieved web page says whatever its author wanted, and a tool result is bytes from a third party. So none of them carry permission. The grant table, the saved instructions, and Slack membership are the only sources, and they are re-read at the moment of use rather than captured at the start of a turn.

The same reasoning keeps secrets out of the model: a model that never holds a credential cannot be talked into printing one.

What is not covered

  • The sandbox shell does not pin the address it validated. Before an outbound request from the shell, Chickpea resolves the hostname fresh, without caching, and rejects private and loopback answers. The request that follows is made by hostname rather than to the address that was checked. A hostname that changes its answer between those two steps leaves a window in which a private address can be reached. The limitation is in the shell library Chickpea depends on and is tracked separately.
  • Memory is not isolation. One Agent has one memory across its DMs and every granted channel. If two jobs must not share what they learn, make two Agents.
  • Publishing is delegation. A channel grant hands that channel’s members everything the Agent can do and reach. Chickpea enforces the grant, not the wisdom of it.
  • One deployment currently serves one Slack workspace. There is no cross-workspace tenancy boundary to review.
  • Node ingress has no durable-admission contract yet. The shared gateway lane relies on Slack retries there; use your own Slack app for reliable Node ingress.
  • The operator holds the rest. HTTPS, least-privilege connections, protected backups, a dedicated deployment identity, and the auth secret and credential keyring retained across restarts.

Reporting a vulnerability

Report privately through the project’s GitHub private vulnerability report form. Never put a vulnerability, a working credential, private Slack content, or exploit detail in a public issue or pull request. Include the affected commit or release, the deployment target, reproduction steps using synthetic data, expected and actual behavior, and the security impact. Redact tokens, setup links, cookies, and workspace identities, and keep any proof of concept confined to a deployment you own.

Before the first tagged release, fixes target main on a best-effort basis. After release, they target the latest published release; older 0.x versions have no separate maintenance branch. There is no response-time SLA.

Next steps

  • Security: the rest of this section: authority and confirmation, data and storage, the shared gateway, telemetry, recovery.
  • How Chickpea works: the same rules followed through one mention and one reply.
  • Deploy and operate: the operator side, including backups and upgrades.
  • Reference: the exact values, including environment variables and telemetry events.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close