sharness.ai / why: the last metre · this page as markdown

Why: the last metre

Status: design. Nothing described here is built. This page describes the problem SHarness started from, in sgit 0.24.0 as observed as of 24 Oct 2026.

The pki.sgit.ai handover protects a vault key while it travels: the sending agent seals it to the receiving agent's public key, and a person carries a QR image they cannot read. It stops protecting the key the moment it arrives.

   travel                          arrival (sgit 0.24.0 today)
 ┌────────────────────┐   ┌──────────────────────────────────────────────────────┐
 │ QR: sealed to the  │──►│ pki-agent open --save  → vault-key-<id>.txt   CLEAR │
 │ receiving agent    │   │ sgit clone <vault key> → argv, shell history, CLEAR │
 │ (person can't read)│   │                          the agent's transcript     │
 └────────────────────┘   │ .sg_vault/local/vault_key            (0600)  CLEAR │
                          │ .sg_vault/local/key-rnd-imm-*.pem    (PKCS#8) CLEAR │
                          │ .sg_vault/local/token                         CLEAR │
                          └──────────────────────────────────────────────────────┘

The transcript is the biggest leak

For an AI agent the worst leak is not the disk. It is the transcript: every command line the agent writes and everything a command prints lands in the model's context and in conversation logs. A key passed as sgit clone <key>, or printed by show-key, is in the transcript for as long as the transcript exists.

The person is the transport

In the handover the person carries things they cannot open: the receiving session's public key bundle one way, the sealed vault key the other.

 receiving session (B)                 person                    sending agent (A)
 ─────────────────────                 ──────                    ─────────────────
 launcher starts sharness.kms
 sharness.kms: make session identity
   RSA-4096 (encryption) + P-256 (signing)
   private halves → memfd_secret, never exported
   print k1 only ──────────────────►  QR (pki.sgit.ai/qr/key/v1)
                                       │ checks fingerprint on pki.sgit.ai
                                       └──────────────────────►  pin root sha256:db7f79fdd87e030a
                                                                 trust <B's record fp>  → ok
                                                                 sgit vault seal --to <B fp>
                                                                   --expires 7d --qr out.png
                                       ┌────────────────────────
                                       │ QR (pki.sgit.ai/qr/sealed/v1, m1 code)
 sgit clone --sealed out.png work ◄────┘
   net → kms: unwrap
   kms: to = me? signature? expiry? sender chains to root? nonce?
   kms → net: derived keys sealed to a one-time key
   fs: writes vault_key.sealed (the m1), never the clear key

Under the design, the receiving agent never sees the key. The sealed m1 itself becomes vault_key.sealed. The full flow and protocol are on Keys and the KMS.

The goals that follow

  1. The clear vault key is never written to disk, never on a command line, never printed. It never enters the transcript.
  2. One place holds the private key: a small KMS process, local and frozen between calls, or remote. Same protocol for both.
  3. Each component does one job and can do nothing else, under its own Process Behaviour Policy, enforced by the kernel and by mutual TLS.
  4. Ephemeral. Identities, certificates, users and policies are made for the session and die with it.
  5. Policies come from outside the agent. The person supplies (or signs) the hash of the policy; the agent cannot widen it.
  6. No server changes. What goes to the vault server is exactly what goes today.

From one fix to a harness

Nothing in that fix is specific to sgit. It describes a launcher and a small set of single-purpose components that any process can run inside: sgit, a shell, an agent loop. That generalisation is SHarness, and sgit's job becomes being compatible with running inside it. See Architecture.

Threat model

Trusted: the kernel, the hardware, and the platform that runs the VM. Root and kernel compromise are out of scope: anything with root on the machine can read any process's ordinary memory. The design shrinks where a key lives; it does not hide it from root.

ThreatExamplePrimary defence (designed)
Transcript leakagethe key printed by show-key, or passed as sgit clone <key>the key never reaches stdout or argv; only sealed forms (m1) and public keys appear
At-rest leakagea backup, a workspace zip, a container image with the folder in itonly sealed files on disk; clear keys live in one process's memory
Prompt injection driving the agenta web page or vault file tells the agent to run show-key or push to another vaultpolicy hash fixed by the person; sharness.net refuses vault ids and hosts not in policy; show-key refused on sealed clones
Prompt injection driving sgit (confused deputy)crafted QR JSON or vault content exploits sgit's parsingstrict input schemas; the exploited process holds no key, has no network, cannot start processes, cannot write outside its folder
A component exceeding its jobsharness.fs tries to reach the KMSper-component uid, Landlock, seccomp, firewall, mutual TLS edge rules
A sealed key stolen from the transcript and replayedthe m1 code copied out of a logthe KMS answers only its bound caller; nonces are single use; responses are sealed to one-time keys

Not claimed: Python cannot guarantee erasure of secrets; expiry on a sealed key is policy enforced by the KMS, not cryptography; a session identity dies with its session, so a restarted session needs a new handover (by design).

Sources: 00-README §1–3, 02-sealed-key-flow-and-kms §1, and the origin article, A vault key that never lands.