v0.20.0
What's new since v0.19.3
This is a feature + hardening release. The headline change is a full PostgreSQL access proxy for agentsh, landed in eleven planned steps (Plan 01–Plan 12); together they add wire-level Postgres interception, classification, policy evaluation, redirect runtime, and a real-Postgres integration suite. Alongside it, a wave of sandboxing and wrap fixes — including the late v0.20.0-rc1 regression #361 — make the wrapper path more robust on hosted runtimes (Vercel/Daytona/Firecracker), and the file-monitor / FUSE / eBPF layers each pick up multiple correctness fixes.
Database access (PostgreSQL)
-
Taxonomy and effects type backbone (#294) — DB Plan 01. Introduces the database access type system: operation taxonomy, effect modeling, and the core types every later plan plugs into.
-
Policy evaluator (#295) — DB Plan 02. The DB policy evaluator that maps taxonomy + effects to allow / deny / approve / redirect decisions.
-
PostgreSQL classifier (#297) — DB Plan 03. SQL → taxonomy classifier covering reads, writes, DDL, DCL, transaction control, and Postgres-specific constructs.
-
PostgreSQL proxy listener skeleton (#298) — DB Plan 04a. Listener, connection acceptance, and the Postgres wire-protocol skeleton.
-
Inbound PostgreSQL handshake + TLS termination (#299) — DB Plan 04b. Startup, AuthenticationOk, parameter negotiation, optional TLS termination of the inbound leg.
-
PostgreSQL upstream wiring + passthrough modes (#300) — DB Plan 04b₂. Dials the configured upstream, supports passthrough and inspect modes for the connection lifecycle.
-
Simple Query path + DBEvent emission (
3da3c49d) — DB Plan 04c. Inspects Simple Query (Q) statements, emits classifiedDBEvents through the same event broker used by exec/audit. -
Extended Query + transaction state machine (#307) — DB Plan 05a. Parse / Bind / Describe / Execute / Sync flow with explicit transaction state tracking.
-
SQL prepared cache + FunctionCall opt-in + classifier escalation wiring (#319) — DB Plan 05b. Prepared-statement cache, opt-in
FunctionCall(F) handling, and classifier escalation hooks for ambiguous statements. -
COPY approval runtime (
3c03e063) — DB Plan 05c. RoutesCOPYoperations through the approval/redirect runtime so bulk loads can be gated like any other DB effect. -
Postgres cancel-request mapping (#321) — Maps inbound
CancelRequestpackets to the right upstream backend so query cancellation works through the proxy. -
Runtime auth events (#324) — DB Plan 07b. Emits structured auth events (success/failure, identity) for the DB proxy alongside normal request events.
-
Real Postgres integration suite (#325) — DB Plan 07c. Adds an integration test suite that exercises the proxy against a real PostgreSQL instance covering the protocol paths landed in 04/05.
-
DB Phase 2 roadmap + catalog resolver foundation (#326) — Roadmap doc and the catalog resolver primitive that later plans build on.
-
Runtime resolution integration (#327) — DB Plan 09. Threads catalog resolution through the runtime so policy decisions reference real schema objects.
-
Policy ergonomics (#329) — DB Plan 10. Higher-level policy shorthands for common DB rules.
-
Redirect planner (#335) — DB Plan 11. Plans rewrites/redirects for matching statements.
-
Redirect runtime integration (
1fda06c1) — DB Plan 12. Wires the planner output into the live proxy so redirects are applied end-to-end. -
Database access unavoidability bundle (
54efd688) — Documents and exercises the security argument that DB policy is unavoidable for proxied connections.
Sandboxing & security — wrap, seccomp, eBPF, ptrace
-
wrap-init refuses when
sandbox.unix_sockets.enabled=false(#362, #363, #364, refs #361) —v0.20.0-rc1regressed every secure-sandbox deployment that disables seccomp at the server level (Vercel Firecracker, Daytona, E2B custom images): the shim engagedagentsh-unixwrapdespiteunix_sockets.enabled: false, loaded a seccomp filter, and the notify-fd handshake failed because the server had no handler — everyexecinvolving env-var expansion or network calls silently exited with empty stdout and exit 1. Fixed in three PRs: the server-side gate (#362), an integration regression guard (#363), and the policy-limits bypass close-out (#364) wheresecure-sandbox's defaultresource_limitshad been keeping the wrapper engaged throughwrapNeedsCgroupBeforeAckeven when no enforcement infrastructure was configured. New unit + integration tests pin all three contracts against the exact config secure-sandbox emits. -
Harden eBPF coverage in wrap (#344) — Tightens how the wrapper attaches eBPF for sessions so coverage holds across the same edge cases that previously slipped through.
-
eBPF attach-only cgroup mode (#347, #348) — New mode where agentsh creates the cgroup and attaches BPF, but does not try to enable controllers in
subtree_control. This is the right behavior on hosts that allow cgroup mkdir+attach but not controller-enable (common on Firecracker / Daytona kernels). -
Warn when eBPF is enabled but cgroups is not (#346) — Surfaces the misconfiguration explicitly instead of silently degrading, and documents the docker prereqs.
-
Pad eBPF
AllowKeyto 32 bytes to match BPF mapkey_size(#350) — Fixes a layout mismatch between userspace key construction and the BPF map definition. -
Pin OS thread before raw
seccomp(2)syscall (#318) — Prevents Go's M-to-P thread movement from delivering theseccomp(2)syscall to a different OS thread than the one carrying the no-new-privs / filter-attach state. -
Link against system libseccomp 2.5 (#316, closes #296) — Uses the system libseccomp at the 2.5 ABI rather than carrying our own.
-
ptrace sessionless pid-attach + reviewed seed helper (#292) — Lets the ptrace tracer attach to a PID without a pre-existing agentsh session, and reworks the seed helper after the security review.
-
Include
agentsh-unixwrapin the defaultmaketarget (#308) — The wrapper binary is now built by the default packaging target. -
Skip
file_monitorauto-enable whensocket_rulesare set (#358, closes #304) — Auto-enabling file monitoring alongside socket rules deadlocked the unixwrap during seccomp setup (file syscalls on the setup path block on a notifFD that hasn't been forwarded yet). Auto-enable now respects the operator's explicit socket-rule intent; users who want both can still opt in withfile_monitor.enabled: true. -
shellparseadmits safe shell-mode flags alongside-c(#330, #331) — Recognizes additional safe shell-mode flags when parsing wrapped shell invocations, so policy sees the right inner command.
File monitor / FUSE
-
Use the backing-path policy in FUSE extra-ops + cross-mount tests (#328) —
checkWithExistresolves to the real backing tempdir before callingCheckFile, soTestFUSE_InterceptsExtraOpsandTestFUSE_CrossMountIntoWorkspaceEmitsCreatenow allow the resolved backing path rather than virtual/workspace/**— keeping the intercepted code paths exercised on hosts where the FUSE mount actually runs. -
Pass through
Fsync/Flush/Lseekon the FUSEfileHandle(#309) — Adds the missing pass-through ops on the FUSE file handle so workloads that rely on them keep working under the monitor. -
Close
eventChanonfs.Mount()error path (#351) —mountFUSEForSessionnow closes the event channel on the mount error path; previously a half-initialized session could leak the channel. -
Make FUSE
MaxBackgroundtunable (#314) —sandbox.fuse.max_backgroundcontrols the kernel-side per-mount FUSE async request queue depth (theFUSE_INIT max_backgroundvalue go-fuse passes). 0 = leave go-fuse's default (12) in place; common tuned values are 32–128 for multi-mount daemons under heavy ptrace+seccomp traffic. -
Don't treat
truncateas destructive undersoft_delete(#310) —truncateis no longer routed through soft-delete, which had incorrectly intercepted it as a destructive operation. -
Filter read-only
openatfile-monitor events (e1438cfd) — Read-onlyopenats no longer produce file-monitor events when they don't change anything actionable. -
Fix FUSE event-channel panic (
ad8d3b64) — Resolves a panic in the FUSE event channel.
DB & event-stream reliability
- Drain watchtower live reader on entry (
55e926c7) — Drains any buffered events from the watchtower live reader when it starts so downstream consumers don't race on stale entries.
Docker test reliability
-
Probe
wait_killablevia unixwrap stderr, notserver.log(#332) — Probing the wrong stream made the docker-test check brittle. -
Drop misplaced
wait_killablecheck (#334) — Follow-up cleanup to the probe path. -
Rocky image path + ubuntu slog stderr leak (#337) — Fixes the rockylinux image reference and stops slog from leaking onto ubuntu's stderr during shim tests.
-
Filter slog from all shim-test captures (ubuntu) (#340) — Generalizes the slog-stderr filter so every shim-test capture is clean.
Demos & CVE write-ups
-
CVE-2026-43284 (Dirty Frag) —
socket_rulesattack surface demo (702c7533) — Before/after demo showing how the v0.19.3dirtyfrag-conservativemitigation closes the attack surface; includes a#304workaround during recording. -
CVE-2026-31431 (Copy Fail) — page-cache LPE before/after agentsh (#306,
2e538f6f,ad45d0cb) — Recordings,demo.html, and narrative updates. The final narrative makes clear thatAF_ALGis blocked by default, and the demo also shows the explicitsocket_ruleform for operators who want to make it visible. -
CVE-2025-32463 (sudo chroot NSS LPE) Docker demo (
30aefc36,a4041fdd,54b92f6d) — Reproducer Docker image with the asciinema cast (and animated GIF), plus thedemo.htmlplayback page.
Documentation
-
DB access spec v0.8 + pressure-test redline (
ff5b0128,92d3f27b,6c814d76) — Pressure-tested the v0.7 db-access-spec, applied the redline as v0.8, and replaced v0.7 in the canonical docs path. -
DB-access Phase 1 implementation roadmap (
137897b3) — The roadmap document that drives Plans 01–12. -
Per-plan design + implementation plans (
b53813c3,b245bb81,66d3d17a,7d37aebe,62cbdf9e) — Implementation plans / designs for DB Plan 01, 11, and 12. -
Plan 05b reconcile with post-05a code state (
38b6a220) — Doc-only follow-up reconciling Plan 05b with what actually landed in 05a.
Validation
The final v0.20.0 Release workflow ran the full matrix and all jobs passed:
goreleaser(binaries, archives, GitHub release)alpine-build(amd64 + arm64)docker-test× 8: alpine, archlinux, debian, debian-trixie, fedora, rockylinux10, ubuntu, ubuntu2204build-macos-app(signed + notarized)publish-homebrew-caskupdate-checksums(non-rc DMG SHA256)
v0.20.0-rc1 was recut three times during the cycle to fold in #362 / #363 / #364; v0.20.0 is tagged on the same commit as the final rc1 (f5833e14).
Full changelog: v0.19.3...v0.20.0