Security

Assume the model has already been turned.

Any channel member can write into the agent’s context, and so can the output of any tool it calls. Every mitigation here is designed to hold when the model is not on your side.

The test

What an attacker gets

These are the cases the phase-1 e2e suite is written to attack. Until it passes, the governed core is not done.

Attempt

A channel member talks the agent into printing its GitHub token.

Nothing to print.

The agent process never receives a credential value. Team sheets, logs, errors and tool definitions carry names. The proxy injects the secret into the outbound call and scrubs known secret values out of the result before it comes back.

Attempt

A poisoned tool result instructs the agent to call an internal admin API.

Refused in the proxy.

The server is not in the channel’s team sheet, so it is not in the tool definitions the agent fetched, and a direct call is rejected anyway. The refusal is a structured result the agent relays; the attempt is in the audit log.

Attempt

Someone asks the agent to deploy to production, urgently, at 2am.

Held for a human.

trigger_workflow is marked approval = "required", so the call stops in the proxy and an Approve card renders in the thread. Whoever clicks is recorded. Destructive verbs default to required whether or not anyone remembered to mark them.

Attempt

A prompt-injected loop tries to burn the month’s token budget in an hour.

Stopped at the meter.

Tokens and tool calls are metered per channel per day in the proxy. The agent loop has its own caps, but they are advisory — the proxy’s meter is the authoritative one, and it does not consult the model.

Attempt

The agent is asked to summarise what a different channel discussed.

No path to the data.

Channel state is one SQLite file per channel. The isolation is the file layout, not a WHERE clause, so there is no query that can join across channels by accident or by instruction.

Attempt

Generated code tries to POST your data to an external host.

No network.

Code execution runs in an ephemeral container with a read-only rootfs, cpu/memory/time limits, and no network unless the team sheet grants an egress allowlist. The proxy invokes the runner, so the execution is audited and budgeted like any other tool call.

Why the split is the whole design

Libero runs as two processes. The gateway and agent talks to Slack and runs the model loop. The tool proxy holds every credential and enforces what each channel may do. They speak over mutual TLS on a private network, and the only thing that crosses is a tool call and its result.

Compromise the agent completely — prompt injection, a malicious skill, a model that simply misbehaves — and the blast radius is bounded by a file in your git repository rather than by the model’s judgement.

The rule is enforced in the source as well as the deployment: packages/agent may never import packages/proxy, checked by an ESLint rule and independently by a grep-level CI job.

What we do not claim

The trust assumptions are stated rather than implied. The operator’s Slack workspace is trusted; individual channel members are not. A malicious operator, a compromised host, and Slack itself are out of scope for v1.

Libero is at phase 0. The proxy described here is the specification, not shipped code. The roadmap is gated so that nothing depending on the proxy ships before the proxy can be attacked and hold.

Reporting a vulnerability

Please do not open a public issue. Use GitHub private vulnerability reporting — Security → Report a vulnerability . We aim to acknowledge within 72 hours.