Files
2026-05-29 18:19:22 +02:00

8.2 KiB

𝄐 fermata

The security layer for AI coding agents.

AI coding agents read files, run shell commands, and inspect output as part of normal work. When they read .env, the secret values get tokenized into the LLM's context window. From there, they can leak into commits, PR descriptions, or API calls the agent makes. The secret is irrecoverably revealed.

fermata sits between the agent and its tools. It blocks operations that shouldn't happen, and scrubs secret values from the output of operations that should.

Caution

Alpha software. Fermata is functional and in daily use by the author, but not widely tested across diverse environments. The core library and Claude Code hook adapters are production-grade; other features are earlier in maturity. Expect rough edges and breaking changes.


The Problem

Traditional security blocks the file. But secrets also appear in shell output, log files, error messages, environment variable dumps, and indirect reads that bypass any access-control list.

Where secrets leak from — blocking the file is necessary but not sufficient

The actual concern is not "can the agent open this file?" but "do secret values enter the LLM context?" An agent can have read access to .env without the secret values being revealed — if the output is redacted before it reaches the model.


How It Works

fermata interposes on the tool lifecycle at two points:

How fermata intercepts — PreToolUse blocks, PostToolUse redacts

PreToolUse — Before the tool executes, fermata checks .botsecrets [policy] and .botignore rules against the operation. A blocked write never happens. A blocked command never runs. Most harnesses already handle basic file blocking, but fermata catches stragglers and works in permissive/yolo modes too.

PostToolUse — After the tool executes, fermata scans the output for secret values. Declared secrets (loaded from files matched by .botsecrets) are replaced using an Aho-Corasick automaton — zero false negatives, sub-millisecond. A secondary heuristic scan catches undeclared secrets that match known formats (AWS keys, JWTs, GitHub PATs, database URLs). This is the primary defense layer.

This means source .env && echo $DB_PASSWORD is caught even though no file read was blocked — the secret value itself is scrubbed from the output before the LLM ever sees it.


Quick Start

Install

cargo install --git https://git.g4b.org/dirigence/fermata --features cli

Requires a working Rust toolchain.

Protect a project

Create a .botsecrets file at your project root — the primary (and usually only) config you need:

# .botsecrets
[files]
patterns = [".env", ".env.*", "secrets.*"]

[policy.write]
patterns = [".claude/**", "vendor/**", "*.lock"]

[policy.bash]
deny = ["rm -rf /", "curl * | sh"]

One file. The agent can read .env freely — fermata redacts the secret values from the output before they reach the model. Write protection and bash safety rules live in the same .botsecrets under [policy].

fermata ships with built-in key patterns (*_KEY, *_SECRET, *_PASSWORD, *_TOKEN, DATABASE_URL, and ~25 more) that cover the common cases automatically.

Note: fermata also accepts fermata.toml as an alias for .botsecrets (same format, .botsecrets takes priority when both exist).

Optionally, add a .botignore for simple path blocking using gitignore syntax:

# .botignore (optional — complements .botsecrets)
vendor/
*.lock

Wire into Claude Code

Add both hooks in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Read|Edit|Write",
        "hooks": [
          { "type": "command", "command": "fermata hook --harness claude" }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|Read|Edit|Write",
        "hooks": [
          { "type": "command", "command": "fermata hook --harness claude --event post-tool-use" }
        ]
      }
    ]
  }
}

PostToolUse redacts secret values from output before they reach the LLM. PreToolUse blocks forbidden writes and dangerous commands.


What Fermata Does Not Do

fermata is a heuristic guard, not a sandbox. It defends against statistical agent behavior — the unguided LLM reaching for .env, the overly-broad glob, the stray cat of a credential file. It does not defend against a deliberate adversary trying to escape the box.

Things fermata cannot catch:

  • Network exfiltration — an agent sending secrets via curl or git push. Use network-level controls (firewall, container networking) for this.
  • Kernel-level file access — a process bypassing tool hooks entirely. Use container isolation or a sandbox for hard filesystem boundaries.
  • Character-by-character reconstruction — an adversarial agent reassembling a secret across multiple tool calls.

These are honest boundaries, not future promises. See docs/threat-model.md for the full analysis.


Configuration

.botsecrets is the primary configuration file. It declares which files contain secrets ([files]), how to redact them ([redaction]), and optionally embeds access-control policy ([policy.write], [policy.bash], [policy.read]). Most projects need only this file. .botsecrets can do everything .botignore can and more.

.botignore uses gitignore syntax to block reads and writes. Useful for monorepo subtree exclusion or teams that prefer gitignore syntax for simple path blocking. Complements .botsecrets but is not required.

See docs/configuration.md for the full reference with examples.


Status

v0.2 — secret filtering engine and policy gate are production-ready:

Component Status Maturity
.botsecrets config + [policy] section Done production
.botignore walker (gitignore semantics) Done production
Known-value redactor (Aho-Corasick) Done production
Heuristic scanner (gitleaks-derived patterns) Done production
Multi-format secret parser (.env, TOML, YAML, JSON) Done production
Claude Code PreToolUse + PostToolUse adapters Done production
CLI: fermata check and fermata hook Done production

Out of scope for v0.2: Codex / Gemini hook adapters, MCP server mode, audit log, filesystem watcher.


Harness Support

Harness Status Mechanism
Claude Code Shipped PreToolUse + PostToolUse hooks
Codex CLI Planned Hook adapter
Gemini CLI Planned MCP server mode
Any MCP agent Planned MCP proxy wrapping existing servers
Any shell-based hook Supported CLI exit codes

The policy engine and redaction logic are identical across all modes. Only the I/O adapter changes.


Background

fermata addresses a novel security concern — reveal: whether secret values enter the LLM context, independent of whether the agent can open a file. This distinction (file identity vs. data content) is explored in:

The .botsecrets format is designed to be the .gitignore of AI agent security: a simple, declarative, harness-agnostic file that every project can drop in. The portable sections ([files], [keys], [redaction], [heuristic]) declare what to protect; the [policy] section adds fermata-specific access control.


Part of Dirigent

Fermata is the security subsystem of Dirigent, a multi-agent orchestration platform. It is developed in the upstream monorepo and exported here for standalone use — no other Dirigent component is required.


License

Licensed under either of

at your option.