Skip to content

v0.13.0 — the zero-trust arc

Choose a tag to compare

@john-broadway john-broadway released this 02 Jul 15:45

The zero-trust arc — a CONTAIN kill-switch and its siblings, a prompt-injection TAINT control, plus an automated PROVE anchor.

Six new opt-in, out-of-band controls, each wired fail-closed at the 5 mutation seams — and each fully inert until its env var is set (zero behavior change by default):

  • CONTAIN kill-switch (PROXIMO_CONTAIN_TRIP_PATH) — while the trip file exists, every mutation is refused before the backend call and audited; checked first at every seam, so it overrides every other gate. Reads and dry-run PLAN stay ungated, so DIAGNOSE still works while contained. The operator's real velocity backstop against a hijacked agent.
  • Independent CONSENT (PROXIMO_CONSENT_DIR / PROXIMO_CONSENT_TTL_SECONDS) — a mutation proceeds only if an unexpired, single-use grant file for this exact plan was placed out-of-band by a human. Closes self-asserted authorization (confirm= is only the agent's own bool). Honest limit: it's a boundary only if the agent's shell can't write the grant dir.
  • Arm-time SCOPE gate (PROXIMO_SCOPE_PATH) — a file-only target allowlist for an armed session; out-of-scope mutations refuse before the backend call, and an unreadable/garbled scope refuses everything.
  • Arm-LEASE TTL (PROXIMO_ARM_TTL + PROXIMO_TOKEN_PATH) — armed write-authority auto-expires N seconds after the arm token's mtime. Closes fail-open-over-time; fail-closed on clock skew, a missing token path, or a garbled TTL.
  • Per-surface ENVELOPE (PROXIMO_FORBID / PROXIMO_RATE_MAX / PROXIMO_RATE_WINDOW) — a deterministic FORBID denylist (composite matching closes sub-action holes) plus a crash-safe, flock-guarded sliding-window rate wall keyed to physical box identity. Honest limit, stated in the code: the rate reservation file is not tamper-evident — CONTAIN's out-of-band kill is the real backstop.
  • TAINT — the prompt-injection mitigation (PROXIMO_TAINT_TRACK / PROXIMO_TAINT_FORBID / PROXIMO_TAINT_REQUIRE_CONSENT / PROXIMO_TAINT_FENCE) — every tool whose return carries guest/external-authored bytes (logs, quarantine mail, exec output, in-guest file reads) is classified, pinned by a completeness test. An adversarial read sets a sticky, file-backed taint marker; once tainted, a pre-declared action set is refused outright (no consent escape) and/or CONSENT becomes mandatory for the in-domain residue. Consent never clears the marker; the fence is advisory and says so. See the rewritten prompt-injection section in SECURITY.md for the tiered mitigation and its honest limits.

Also in this release:

  • Off-box PROVE anchor (audit_anchor.py) — automates pinning the audit-ledger head to a write-once path; the export never re-pins to a moved head, so detecting a truncation can't overwrite the good pin.
  • pve_acl_prune — the enforcement counterpart to pve_overbroad_grants: revoke a flagged over-broad grant (optionally re-grant narrower), routed through the full spine. 351 → 352 tools.
  • Security hardening: proximo.env now actually loads at startup (closes a footgun that could leave CONSENT silently inert); the PROVE ledger append is O_NOFOLLOW-hardened against symlink redirection; the rate wall is evaluated after consent, so refused mutations spend no budget.
  • Fixed: pve_acme_plugin_create/_update crashed whenever dns_api was set (param collision — the DNS-plugin ACME path was unusable); golden request-shape sweep now covers every wrapper.
  • Docs truth-sized: SECURITY.md gains the two-deployment trust model and a controls-and-defaults table — which gates are on by default, which are opt-in, and what each honestly holds.

Full suite 5,068 green (3 by-design skips), ruff + pyright clean. Everything here is backward-compatible: with no new env vars set, 0.13.0 behaves like 0.12.0 (plus the acme fix).