Releases: cavi-ai/secure-agent
Release list
v1.1.0 — actionable criticals, session trees, privileged ES collector
The v1.1.0 delta over v1.0.0 (which was effectively the last RC).
Highlights
- Actionable criticals — every flag opens a decision sheet: evidence chain, local advisor verdict, one-click dispositions (allow host / dismiss flag class / rotate credentials / kill). Applied flags dim with a DONE pill and stop counting as critical.
- Mutes that work — localhost-alias-aware suppression, retro-acknowledges existing flags, visible+revocable in Settings → Decisions.
- Agent session trees — harness → session → subagent grouping with brand icons and family memory. 400 processes render as ~28 sessions.
- Process transcripts — live per-pid event feed with kill confirmation.
- Privileged ES collector — file telemetry via a root LaunchDaemon (
--es-collectormode → spool → user daemon). One-click install, guided permission card. - Advisor that works with reasoning models — qwen3 et al supported natively (think:false, reasoning-field fallback, real token budgets). Verdicts map to executable verbs with Apply buttons. Idempotent re-triage on demand.
- Stability — "Disconnected" flapping fixed (O(1) status joins), SSE reconnect crash-loop fixed, pause semantics corrected, update installs frozen-UI-free and signature-verified.
Signed with a stable identity
This release is signed with an Apple Development certificate (Team Y76GMV87GM) — Full Disk Access and other TCC grants now survive updates. Notarization is not applied in this build; first launch requires right-click → Open. Public distribution should move to a Developer ID + notarization.
Install
Mount the DMG, drag Secure Agent.app to Applications. SHA-256 in checksums.txt (also below).
454aee711141d87631781491d64e186be648c2c19ed4ac087df48a449cd852ab SecureAgent-v1.1.0.dmg
PR #68 has the full change list.
v1.0.0 — Little Snitch for AI agents
Little Snitch for AI agents: see what your agents send, catch secrets before they leak, and know at a glance whether to care.
The first stable release of secure-agent — a lightweight, always-on security monitor for local AI coding agents (Claude Code, Cursor, Codex, opencode) on macOS 14+.
Highlights
- In-harness secret guard — PreToolUse gating with interactive Allow/Deny prompts; directory-scan gating for Grep/Glob; harness self-protection (settings & hook scripts are not agent-writable)
- Egress secret-leak firewall — opt-in local MITM proxy: known-secret fingerprints (salted HMAC), 20+ typed patterns, monitor-by-default with per-rule promote-to-block
- Sliding-window correlation — sensitive read → foreign connection → flag with full evidence chain, incident reports with rotation checklists
- The local advisor — opt-in, loopback-only, advisory-only: a locally served model (managed or your existing Ollama/MLX server) triages flags, writes incident narratives, and gives injection second opinions. Verdicts never change enforcement
- Console — live security console: posture banner, evidence chains, activity trends (24h/7d), session drill-down, sparkline, mute dispositions, allowlist suggestions with advisor assessments
- Menubar — glanceable 3-state hero popover, full Settings window, onboarding wizard, weekly digest, one-click updates
- Self-updating — Stable channel (this release, SHA-256-verified against
checksums.txtbefore mounting) and a nightly channel for repo checkouts
Install
Download SecureAgent-v1.0.0.dmg, drag Secure Agent.app to /Applications, and launch it — the first-run wizard walks through hooks, Full Disk Access, and the optional local advisor.
Verified end-to-end on every CI run: Go, Swift, Python, JS (unit + DOM), and a full e2e smoke (flag → incident → guard round-trip → fleet webhook → SSE → console auth → advisor verdict).
Checksums for the DMG are in checksums.txt — the in-app updater verifies against exactly this file.
v0.9.0-rc.2 — audit hardening, SSE push, console fix, Linux daemon
Release candidate 2. Ad-hoc signed DMG — right-click → Open on first launch (notarized builds are planned for v1.0).
Release candidate 2: the full audit hardening pass (hooks, daemon,
menubar, CI/packaging), SSE push for both UIs, the console-auth
fix, session evidence chains, and the guard policy editor.
Linux support
- The daemon is now platform-portable (pure Go, no cgo):
/proc-based
process source and socket lister, SO_PEERCRED peer credentials, eslogger
gated behind an availability check (Endpoint Security is macOS-only —
file telemetry degrades to the transcript scanner on Linux, everything
else is identical). NewLinux build + vet + testCI job on ubuntu-latest
enforces it; darwin/linux factories (NewProcSource,NewSocketLister,
NewPeerChecker) keep platform code in build-tagged files.
Security fixes (hooks)
- Shell
-cbypass closed.sh/bash/zsh/dash/kshpayloads are now
recursively analyzed (depth-capped). Previouslyzsh -c "security dump-keychain"bypassed every check, including the keychain total-ban. - Executor bypasses closed.
xargsis no longer stripped as a wrapper
(echo ~/.zshrc | xargs rmwas allowed);find -exec/-deleteover protected
paths is denied; archivers (tar/zip/ditto/7z) over protected
directories are denied as bulk exfiltration. - Case-folding on APFS. Path classification is case-insensitive
(~/.ZSHRCis~/.zshrcon a case-insensitive volume). - Wider credential surface. Added
~/.netrc,~/.gnupg/**,
~/.kube/config,~/.docker/config.json,~/.npmrc,~/.pypirc,
~/.config/gh/hosts.yml, and*.pem/*.p12/*.pfxto the never-print set.
.pubpublic keys are now correctly allowed (they are meant to be shared). - Obfuscated inline writes denied. Interpreter
-ccode combining a file
write with runtime path composition (chr()/base64/env lookups) is denied as
interpreter-obfuscated-write. - chflags fixed both ways. Unlock detection now matches a known flag set
(nouchg/noschg) instead of "starts with no" — sochflags nodump(a
hardening flag) is allowed, whilechflags -R nouchg ~is denied. - No secrets in the audit trail. Denied commands are redacted (passwords,
tokens, bearer strings, PEM headers) before hittingsecret-guard.jsonl/
activity.jsonl, and both logs are now0600in0700dirs. - Corrupt guard config fails closed. A truncated
guard-modes.json/
guard-cwd-overrides.jsonnow denies (and logs loudly) instead of silently
reverting every rule tomonitor. - Injection scanner robustness. NFKC normalization, zero-width/format char
stripping, and Cyrillic-homoglyph folding before matching; added
forget…/do not follow…/new goal:pattern families; recursion is
depth-bounded and a scanner crash now emits{}instead of dying with no
JSON.
Security fixes (daemon)
- Guard broker data race fixed (
Resolveiterated a waiter's channel slice
after dropping the lock whileRequestappended under it). New-race
regression test. - Authorization wired correctly.
authorizenow uses the role methods
(canRead/canDecide/canMutate): tagged agents may read and ask
/guard/decision(previously 403, which broke the prompt flow), but can
never mutate. - CA key regeneration actually lands at 0600.
os.WriteFilepreserves an
existing file's mode, so a regenerated key inherited the old world-readable
perms; all security-state files now write via temp+fsync+rename (atomic and
crash-consistent). - Salt rotation is loud, never silent. A truncated/unreadable salt file is
an error with operator instructions instead of silently minting a new salt
that orphans every registered fingerprint. - Fingerprint ingest refuses to purge. A run that reads zero fingerprints
while every source failed returns an error instead of an empty set that
would silently wipe the registry; oversized lines no longer truncate scans. - Config overlay errors are visible (log warnings on unreadable/malformed
YAML), andLoadvalidates values that would panic at runtime
(net_sample_interval_ms <= 0panicstime.NewTicker). - Store correctness.
SetIncidentStatususesRowsAffectedinstead of
SELECT changes()on a possibly-different pooled connection (spurious
404s); incident IDs now include the flag ID (same-second same-pid flags no
longer overwrite each other's evidence);flagstable has a retention cap
like the other tables;QueryEventsreturnssession_id; timestamps are
stored UTC-normalized. - Proxy correctness. Blocked CONNECT request bodies are drained before the
next read (keep-alive tunnels no longer desync); the plain-HTTP path reuses
one transport; token comparison is constant-time. - Resource bounds. Fleet deliveries capped at 64 in flight (dropped and
counted beyond that); the correlator's uninspected-egress set is capped;
the tagger prunes dead pids (also fixes recycled-pid tag inheritance);
transcript scanner prunes rotated files and caps line length; eslogger
zombies reaped; reverse DNS is async with a deadline instead of blocking
the sampler; the event bus refuses subscriptions after close; API POST
bodies are size-limited;/guard/resolvevalidates method and id;
lsoffailures are logged. - Collector read auth.
-read-token(or
SECURE_AGENT_COLLECTOR_READ_TOKEN) gates/fleet,/nodes/*, and/;
binding a non-loopback address without one logs a loud warning. agent-env.shvalues are shell-quoted — paths with spaces (e.g.
Application Support) no longer break the snippet, and metacharacters
can't inject into the sourcing shell.
Menu bar app
- Transport hardening. The unix-socket client now has connect/send/recv
timeouts (a wedged daemon no longer hangs the app or leaks blocked
threads), parses the HTTP status line (non-2xx is an error, not JSON), and
handles chunked transfer-encoding. Query parameters from daemon-supplied
values are percent-encoded. - No more fail-open guard UI.
/guard/pendingand/guard/rulesdecode
strictly; a malformed response surfaces an error instead of silently
showing "nothing to approve". - No first-launch notification storm. The first fetch seeds the
notification baseline; only genuinely new flags alert. Notification bodies
no longer leak paths/hostnames to the lock screen. - Honest actions. Kill asks for confirmation and reports refusal; a guard
decision that fails to reach the daemon tells you it wasn't recorded;
disconnect clears all daemon-derived state instead of showing stale data;
a daemon that crashed past the restart limit gets an in-app "Restart"
button instead of a silent permanent "Disconnected". - Incident remediation in the popover. Tapping an incident opens the
daemon-generated rotation checklist (previously only in the web console). - Fetch loop is serialized (no overlapping out-of-order polls), the unused
1 Hz/eventsfetch is gone, hook detection requires all three harnesses
(allSatisfy), the hook self-test no longer pipe-deadlocks, and
guard-modes.jsonwrites are atomic.
CI / packaging
- GitHub Actions are SHA-pinned with
permissions: contents: read. e2e_smoke.shkills all background processes on any exit (failures used to
orphan the daemon/collector with their state dir deleted underneath).make_dmg.shfails loudly when notarization was requested but fails.make_app.shsanitizes git-derived strings before plist interpolation.uninstall.shonly removes hooks it actually installed and lists leftover
state instead of claiming "completely uninstalled".run_e2e_verbose.pyanchors at the repo root and always reaps the daemon.
Menu bar: SSE push replaces 1 Hz polling
- The menu bar app now consumes the daemon's
/events/streamSSE feed:
guard prompts arrive at push latency instead of up-to-1s poll latency,
and the idle poll drops to a 30s status cadence. Falls back to the 1 Hz
poll when the endpoint is unavailable (503 from an older daemon) and
reconnects with capped exponential backoff + jitter on transport failure.
The stream's 15s heartbeat doubles as the liveness watchdog (45s idle =
dead connection, reconnect). - Daemon publishes two new bus event kinds for the guard lifecycle:
guard-prompt(a prompt was enqueued) andguard-resolved(a prompt was
resolved), letting every connected UI refetch immediately. - Enforced by
e2e_smoke.sh: the stream must carry both guard lifecycle
events during the guard round-trip.
Web console: actually works now, and live
- Fixed a broken headline feature: the dashboard at
http://localhost:8443/dashboard/loaded, but every telemetry fetch hit the
proxy listener's token challenge (407) — the console rendered a permanent
offline banner with no data. The proxy port now serves the console's API
endpoints behind a new per-install console token
(~/.config/secure-agent/console-token, 0600) — deliberately distinct from
the proxy token, which agents carry in their environment and could
otherwise trade for telemetry reads and guard self-approval.
/guard/decisionstays off the HTTP listener entirely (peer-attested unix
socket only). - The console now consumes
/events/stream(SSE) with a 2s polling fallback
and a 30s slow refresh for status — guard prompts and flags appear at push
latency. - The menubar's Open console passes the console token automatically; the
page strips it from the address bar after lifting it into memory. - Enforced by
e2e_smoke.sh: 403 without a token, 403 with the proxy token,
200 with the console token; plusTestConsoleAPIGatein Go.
Features & follow-ups
- Session evidence chains survive the store. The
flagstable now
persistssession_id(with an in-place migration for existing databases —
...
v0.9.0-rc.1
secure-agent v0.9.0-rc.1
First release candidate of the AI-agent security monitor: egress secret-leak firewall, interactive Directory Guard, and fleet-ready telemetry for macOS.
RC disclaimer. The DMG is ad-hoc signed — right-click → Open the first time. Notarized builds planned for v1.0. Feedback wanted before the v1.0 tag.
Highlights
- Peer-auth control socket — kernel-attested pid/uid on every API connection;
/killrestricted to recognized agent processes - Directory Guard — monitor/prompt/deny modes, per-project (
cwd_overrides) policies, native prompts with Deny as the safe default - Fleet oversight — signed webhooks (
X-SecureAgent-Signature), stablenode_id, session identity through evidence chains, full CLI parity, and a reference collector (cmd/secure-agent-collector) - Operator UX —
/postureheadline, incident ack/resolve workflow, SSE live stream, console drill-down, onboarding hook self-test, human-language guard prompts - Detection depth — TCC-tamper and keychain-CLI correlator rules; proxy authentication token
See CHANGELOG.md for the complete list.
Install
- Download
SecureAgent-v0.9.0-rc.1.dmg, open it, drag Secure Agent.app to Applications. - Right-click → Open the first time (ad-hoc signature).
- The setup wizard installs harness hooks (Claude / Cursor / opencode) and walks through Full Disk Access.
Monitoring runs only while the app runs — no LaunchAgent, nothing in the background.
Verification
- Go (vet, test,
-race), Swift package tests, 138 hook test cases, and an end-to-end smoke test all green in CI. - The shipped daemon reports its version:
curl --unix-socket ~/.config/secure-agent/daemon.sock http://unix/fleet | jq .version→v0.9.0-rc.1.
Feedback wanted before v1.0: issues.