Skip to content

0.10.0

Choose a tag to compare

@batrapulkit batrapulkit released this 14 Oct 11:26
95f5787

An agent can't approve itself, observe mode with a weekly report, chains across conversations

Security fixes: upgrade

An audit of our own claims (AUDIT.md) found two ways a connected agent could approve its own held action.
Both are fixed, and a test suite now plays the agent trying each way in (tests/test_approval_integrity.py):

  • reading Squidbrake's approval-link secret with its file tools, then signing an approval link
  • running squidbrake add-key NAME --approver, then approving with the new key

These are now blocked in code, before your rules and in observe mode too:

  • reading or writing Squidbrake's keys, link secret, ledger key and database
  • the key and stop commands (add-key, remove-key, resume, feedback, integrity)
  • calling the approval API from the agent's own tools
  • reading browser profile storage

Each attempt is recorded as security.self_approval_attempt, sent to your SIEM, and sent wherever approvals go.

These now wait for a person:

  • editing the installed package
  • installing another version of it
  • a lasting GATEWAY_* or SQUIDBRAKE_* variable
  • a gateway started with sign-in off

Try it without it stopping anything

  • Observe mode. Run squidbrake connect all --mode observe, or set mode: observe in rules.yaml. Nothing is
    blocked or held. What would have been blocked or held is recorded.
  • Mode per rule. A rule or sequence can set its own mode: enforce | observe. For example: enforce the
    catastrophic ones first, observe the rest.
  • The weekly report. squidbrake report --week (Markdown, or --json) covers:
    • actions seen, held and blocked, and what would have been held or blocked
    • the false-positive rate
    • decision time (p50, p95 and p99)
    • the top 3 chains it caught, in plain words
  • Mark false positives. Use "This was legit" on a hold or block in the dashboard, or
    squidbrake feedback EVENT_ID legit. The rate is counted per rule and per week.

Chains across conversations and agents

  • What an agent's earlier steps give it is kept until it expires, across restarts. On your own computer that's
    across all your agents; on a team gateway, across the agents that work for one person. squidbrake capabilities
    lists it.
  • Outside content read in one conversation now counts in the next.
  • A refund loop split across two agents is counted as one loop.
  • New in bench/chains: a docs page read one day, and the config posted to its collector the next day by another
    agent. Reading one step at a time lets it run. With chains, it's held. Result: 64 of 65 harmful steps stopped,
    with 3 false positives out of 41 routine steps.

Coverage and tamper checks

  • Commands sent over ssh, docker exec and kubectl exec are read like local ones.
  • A script the agent changed and then runs is flagged. Set edited_then_run: review to hold it too.
  • Squidbrake checks every minute that its hook in each agent, rules.yaml and the installed program haven't been
    changed. With integrity: fail_closed, risky actions are blocked until you run squidbrake integrity accept.
  • squidbrake audit verify checks the whole record and names the first broken link.
  • squidbrake doctor now lists, per agent, what its hook checks and what it doesn't.

Changed defaults

  • when_unreachable: block_risky is the new shipped default. While Squidbrake is down:

    • what your rules already allow (reads, everyday coding work) still runs, unrecorded
    • anything that would wait for a person or be blocked doesn't run
    • neither does any command that can't be undone or can't be read

    The previous default (block) stopped everything. An unedited rules.yaml is updated to the new default on start.
    To keep the old behaviour, set when_unreachable: block.

  • The shipped runaway-refunds rule counts across all your agents (scope: identity), not one agent at a time.

  • taint_checks.scope: identity: prompt injection is remembered across conversations. Set it to session for the
    old behaviour.

What it doesn't stop

THREAT_MODEL.md lists it, with the test behind each claim. In short: code that isn't read
before it runs, what happens inside an allowed program or an MCP server, and AWS IAM reach (not built yet).

Also corrected

bench/compare said Squidbrake stopped all 12 steps. Counted the way CI counts, it's 11 of 12: holding the Postmark
send doesn't stop the hidden BCC added inside the server.

Thanks to @GreedyC (#85), @escher-m (#86) and @lauren-paang (#71) for their pull requests in this release.

Install this version (0.10.0)

Windows (PowerShell):

$env:SQUIDBRAKE_VERSION="0.10.0"; irm https://pilots.squidbrake.com/install.ps1 | iex

macOS / Linux:

curl -fsSL https://pilots.squidbrake.com/install.sh | SQUIDBRAKE_VERSION=0.10.0 sh

With pip: pip install squidbrake==0.10.0. Docker: docker pull ghcr.io/batrapulkit/squidbrake:0.10.0

Running the line again without SQUIDBRAKE_VERSION goes back to the newest. Every version:
https://github.com/batrapulkit/squidbrake/releases