cli.sgit.ai / Dev packs / Sealed vault keys, 04: environment evidence

04. Environment evidence

Everything below was observed on 24 October 2026 in a Claude agent workspace (claude.ai, cloud session). Re-run the probes before relying on them elsewhere: other platforms, and later versions of this one, may differ.

How to read this page. The agent runs as root inside its own microVM. That is the platform's design: the VM is the isolation boundary, and inside it the agent is meant to have the whole machine. Nothing on this page is a finding against the platform. The probes measure what sgit's components could lock down inside that boundary, and they show why the strongest form of this design needs the platform's help (00 §6).

1. The environment

FactObserved
IsolationFirecracker microVM; PID 1 is /process_api --firecracker-init … (not systemd)
OS / kernelUbuntu 24.04.5, Linux 6.18.44, x86_64
Agent's identityuid 0 (root), full capability set (CapEff 000001fffeffffff)
Hardening presentno seccomp, NoNewPrivs 0, no Yama (/proc/sys/kernel/yama absent)
Core dumpsulimit -c 0; core_pattern = core
Python / cryptoPython 3.13.17; cryptography 50.0.1
sgitpip install sgit-ai → 0.24.0 (the version the article analysed)
Hardware keysno /dev/tpm*
Egressevery outbound HTTPS goes through a platform proxy on a loopback port; send.sgraph.ai, pki.sgit.ai, cli.sgit.ai reachable (HTTP 200)
Scratch spacethe agent's scratchpad is root-only (other uids get EACCES)
Process lifetimeper the platform: a process detached with nohup/& is stopped within minutes of the agent's reply; a tool-managed background process can run up to 2 h. Not measured.
Firewall toolsiptables, nft present; OUTPUT policy ACCEPT, empty
cgroupsv1 hierarchy: blkio, cpu, cpuacct, cpuset, devices, freezer, memory, pids, systemd, unified
FUSE/dev/fuse (root-only), fusermount3 present

Kernel configuration (/proc/config.gz)

OptionValueRelevance
CONFIG_SECURITY_LANDLOCKy (ABI 7)file + TCP port sandboxing
CONFIG_SECCOMPysyscall allowlists
CONFIG_SECRETMEMymemfd_secret
CONFIG_CGROUP_FREEZERyfreeze the KMS between calls
CONFIG_CHECKPOINT_RESTOREyCRIU possible (binary not installed)
CONFIG_FUSE_FSysgit-fs as a mount
CONFIG_ASYMMETRIC_KEY_TYPEykernel asymmetric keys …
CONFIG_PKCS8_PRIVATE_KEY_PARSERnot set… but no private keys → kernel-held decryption unavailable
CONFIG_TRUSTED_KEYSnot set(needs TPM anyway)
CONFIG_ENCRYPTED_KEYSysymmetric blobs only

2. Article claims checked against sgit 0.24.0

ClaimResultMethod
pki keygen makes RSA-OAEP 4096 + ECDSA P-256, sha256:+16 hex✔ran it with a throwaway HOME
Private keys encrypted with PBKDF2 at 2,048 iterations✔ INTEGER :0800 on both private_key.pem and signing_private.pemopenssl asn1parse
Secrets__Store fixed salt✔ salt = f'{SECRETS_SALT_PREFIX}:master'source
BestAvailableEncryption used for keys✔ crypto/PKI__Crypto.py:37source
Key read in many places65 references in 23 files for _read_vault_key|load_vault_key|vault_key_path (broad grep incl. imports; article counts 27 read sites in 17 files)grep
Public key files modepublic_key.pem 0644; private PEMs 0600ls -l

3. Memory

ProbeResult
prctl(PR_SET_DUMPABLE, 0) then root reads /proc/<pid>/memsecret found: root's CAP_SYS_PTRACE overrides
mlock / mlockallsucceed
memfd_secret (syscall 447)available
root reads a memfd_secret page through /proc/<pid>/memEIO
RSA-4096 OAEP open → copy into secret page → no scrub; root sweeps all readable mappingsone copy found in anonymous heap
same, with scrubbing the returned bytes (and the test's own original)no copy found
RSA-4096 OAEP open time3.2–3.6 ms
kernel keyring add_key (process keyring)works
user keyring entry persists across separate agent tool calls✔
key in uid sgit-dec user keyring, searched by uid sgit-runENOKEY
that key in root's /proc/keysnot listed
add_key("asymmetric", <PKCS#8 RSA-4096 DER>)EBADMSG (parser not built)
cgroup freezer: freeze / thaw a process (avg of 20)0.28 ms / 0.13 ms; frozen state D

4. Process isolation

ProbeResult
create system users (useradd -r -M -s nologin)✔
setpriv --reuid --regid --clear-groups --no-new-privs --inh-caps=-all --bounding-set=-allCapEff 0, CapBnd 0, NoNewPrivs 1
other uid reads a root filedenied
unshare --net then connect outENETUNREACH (101)
unshare --user --map-root-user --pid --fork --mount-proc✔
Landlock ABI7
RLIMIT_NPROC=0 then forkEAGAIN (blocked)
Landlock fs (ro /usr /etc /lib /lib64 /proc): read /etc/hostnameallowed
Landlock fs: read a file elsewhereEACCES
Landlock fs: write /tmp/xEACCES
Landlock net (connect only to the proxy's port): proxy portallowed
Landlock net: 127.0.0.1:22, 1.1.1.1:443EACCES
iptables -A OUTPUT -m owner --uid-owner <user> -j REJECTaccepted
SO_PEERCRED on Unix socketreturns pid, uid, gid
abstract-namespace Unix socket✔
ephemeral user + firewall rule + locked launch + teardown (avg of 10)49 ms
new net + pid + mount namespaces (avg of 10)3.7 ms
seccomp filteravailable, not tested

5. Footprint (strace -f, file/network/process/ipc)

CommandPaths opened OKFoldersDistinct syscallsexecvesocket/connect
python3 -I -c print(1)39213110
sgit --version1,1042123810
sgit pki list1,1092153910
import sgit_ai.cli.CLI__Main529 modules, 146 ms
bare python3 -I -c pass start15 ms

6. Transport (Python ssl, TLS 1.3, P-256; server is a thread in the benchmark process)

Connect + handshake600 B round tripBulk (64 MiB echo)
TCP plain0.10 ms15 µs~300 MB/s
TCP mutual TLS3.2 ms67 µs~320 MB/s
Unix plain0.09 ms56 µs~320 MB/s
Unix mutual TLS3.4 ms74 µs~420 MB/s
pipe to a separate processn/a34 µsn/a
TCP mutual TLS without server TCP_NODELAY46 ms

Session CA + four role certificates (P-256, 2 h): 24 ms.

Edge enforcement with roles in subjectAltName URIs, policy fs←{cli}, net←{cli}, kms←{net}:

cli → fs   OK        fs  → kms  DENY
cli → net  OK        cli → kms  DENY
net → kms  OK        fs  → net  DENY

Figures are from the final of three runs. Across runs, round trips and bulk varied by up to ~25% (TCP mutual TLS bulk: 250, 275, 318 MB/s; Unix mutual TLS bulk: 349, 378, 418 MB/s); handshake times were stable. Microsecond figures are noisy because the server thread shares Python's interpreter lock with the client: treat them as upper bounds.

7. Left in the environment

Users sgit-dec, sgit-run; /opt/sgit-probe/ (probe scripts); a user-keyring entry sgit:persist-probe (root). All die with the VM.

This page as markdown · its source, admin/content/dev/sealed-vault-keys/04-environment-evidence.md