Skip to content

Releases: cavi-ai/secure-agent

v1.1.0 — actionable criticals, session trees, privileged ES collector

Choose a tag to compare

@sasan1200 sasan1200 released this 14 Sep 13:18
v1.1.0
ad21643

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-collector mode → 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

Choose a tag to compare

@sasan1200 sasan1200 released this 10 Sep 06:59
640a57e

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.txt before 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

Choose a tag to compare

@sasan1200 sasan1200 released this 07 Sep 19:23
5351b73

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). New Linux build + vet + test CI job on ubuntu-latest
    enforces it; darwin/linux factories (NewProcSource, NewSocketLister,
    NewPeerChecker) keep platform code in build-tagged files.

Security fixes (hooks)

  • Shell -c bypass closed. sh/bash/zsh/dash/ksh payloads are now
    recursively analyzed (depth-capped). Previously zsh -c "security dump-keychain" bypassed every check, including the keychain total-ban.
  • Executor bypasses closed. xargs is no longer stripped as a wrapper
    (echo ~/.zshrc | xargs rm was allowed); find -exec/-delete over 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
    (~/.ZSHRC is ~/.zshrc on a case-insensitive volume).
  • Wider credential surface. Added ~/.netrc, ~/.gnupg/**,
    ~/.kube/config, ~/.docker/config.json, ~/.npmrc, ~/.pypirc,
    ~/.config/gh/hosts.yml, and *.pem/*.p12/*.pfx to the never-print set.
    .pub public keys are now correctly allowed (they are meant to be shared).
  • Obfuscated inline writes denied. Interpreter -c code 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" — so chflags nodump (a
    hardening flag) is allowed, while chflags -R nouchg ~ is denied.
  • No secrets in the audit trail. Denied commands are redacted (passwords,
    tokens, bearer strings, PEM headers) before hitting secret-guard.jsonl /
    activity.jsonl, and both logs are now 0600 in 0700 dirs.
  • Corrupt guard config fails closed. A truncated guard-modes.json /
    guard-cwd-overrides.json now denies (and logs loudly) instead of silently
    reverting every rule to monitor.
  • 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 (Resolve iterated a waiter's channel slice
    after dropping the lock while Request appended under it). New -race
    regression test.
  • Authorization wired correctly. authorize now 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.WriteFile preserves 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), and Load validates values that would panic at runtime
    (net_sample_interval_ms <= 0 panics time.NewTicker).
  • Store correctness. SetIncidentStatus uses RowsAffected instead 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); flags table has a retention cap
    like the other tables; QueryEvents returns session_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/resolve validates method and id;
    lsof failures 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.sh values 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/pending and /guard/rules decode
    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 /events fetch is gone, hook detection requires all three harnesses
    (allSatisfy), the hook self-test no longer pipe-deadlocks, and
    guard-modes.json writes are atomic.

CI / packaging

  • GitHub Actions are SHA-pinned with permissions: contents: read.
  • e2e_smoke.sh kills all background processes on any exit (failures used to
    orphan the daemon/collector with their state dir deleted underneath).
  • make_dmg.sh fails loudly when notarization was requested but fails.
  • make_app.sh sanitizes git-derived strings before plist interpolation.
  • uninstall.sh only removes hooks it actually installed and lists leftover
    state instead of claiming "completely uninstalled".
  • run_e2e_verbose.py anchors 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/stream SSE 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) and guard-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/decision stays 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; plus TestConsoleAPIGate in Go.

Features & follow-ups

  • Session evidence chains survive the store. The flags table now
    persists session_id (with an in-place migration for existing databases —
    ...
Read more

v0.9.0-rc.1

v0.9.0-rc.1 Pre-release
Pre-release

Choose a tag to compare

@sasan1200 sasan1200 released this 03 Sep 22:03
d4d94a6

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; /kill restricted 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), stable node_id, session identity through evidence chains, full CLI parity, and a reference collector (cmd/secure-agent-collector)
  • Operator UX/posture headline, 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

  1. Download SecureAgent-v0.9.0-rc.1.dmg, open it, drag Secure Agent.app to Applications.
  2. Right-click → Open the first time (ad-hoc signature).
  3. 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 .versionv0.9.0-rc.1.

Feedback wanted before v1.0: issues.