No description
  • Rust 93.1%
  • Shell 3.6%
  • Dockerfile 1.2%
  • Makefile 1.2%
  • HCL 0.9%
Find a file
Vincent K 153ed965c3
feat: two-party confidential sim POC on Caution
Broker pins B's binary by hash, gates A's access by token hash, and runs the binary in a
jail (namespaces, chroot, nobody, seccomp socket allowlist), re-pushable after it exits.
Includes rocket-sim, the demo CLI (plaintext/STEVE), an escape probe, QEMU jail tests, README.
2026-10-30 18:37:46 +01:00
broker feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
cli feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
examples feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
rocket-sim feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
scripts/qemu-jail-test feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
.dockerignore feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
.gitignore feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
Cargo.lock feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
Cargo.toml feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
caution.hcl feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
Containerfile feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
Makefile feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
README.md feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00
rust-toolchain.toml feat: two-party confidential sim POC on Caution 2026-10-30 18:37:46 +01:00

Two-party confidential processing on Caution

Company B sells access to rocket-sim, a flight simulator it shows no one, running on its own Caution cloud. Company A, B's customer, has confidential rocket designs and wants simulated launches without B ever seeing the designs or the results.

The pitch: open the jail, not the code. A never sees B's binary. It reviews a small open jail, proves with caution verify that the jail is what runs, and only A's token gets in.

How it works

  • Two binaries. The Caution app is broker (open, built by the Containerfile, measured). B's simulator rocket-sim is never in the image: B uploads it after boot, encrypted to the verified enclave.
  • Two pins. caution.hcl pins the SHA-256 of B's binary and the SHA-256 of A's token as broker args, so both are measured. The broker runs only the pinned binary, and relays only requests carrying A's token (inside STEVE). B itself gets 401.
  • The jail. The simulator runs with an empty network, an empty chroot, as nobody, under a seccomp filter (no vsock to the host). Any failed step and nothing runs.
  • The probe. The broker tries eleven ways out of the same jail and reports each one, so A can watch it hold.
sequenceDiagram
    participant A as Company A (customer)
    participant E as Enclave on B's Caution cloud
    participant B as Company B (provider)

    A->>B: 1. token hash (A keeps the token)
    B->>E: 2. deploy the broker with both hashes pinned
    Note over E: hash check, token check and jail are up. No simulator yet.
    B-->>A: 3. repo, deploy commit, app URL
    A->>E: 4. review the jail, caution verify
    E-->>A: PCRs match the commit A read
    B->>E: 5. verify, upload the secret simulator (encrypted)
    Note over E: hash matches, simulator starts in the jail
    A->>E: 6. run the probe
    E-->>A: 11 of 11 escapes blocked
    A->>E: 7. design and launches, with A's token (encrypted)
    E-->>A: results, encrypted to A
    B->>E: 8. try with its own token
    E-->>B: 401
    B->>E: plain HTTP to the host
    E-->>B: 403 e2e_required
    A->>E: 9. wipe its data
    B->>E: tear the enclave down

What A reviews: broker/src/jail.rs (seven numbered steps, ~190 lines), broker/src/seccomp.rs (~110 lines), and caution.hcl: A's own token hash, B's binary hash, no --dev, no egress, only port 8080.

What's in the repo

Each part plays a role in the story: the open app A reviews, B's secret program, and the tools both companies use.

broker/                   the open Caution app, the only thing Caution builds and measures
  src/jail.rs             the jail around B's program               (A reviews)
  src/seccomp.rs          the system calls the jail refuses         (A reviews)
  src/payload.rs          checks B's upload against the pinned hash
  src/auth.rs             checks A's token on every request
  src/relay.rs            passes A's requests to B's program
  src/launch.rs           starts B's program inside the jail
  src/probe.rs            the built-in escape probe
  src/server.rs           the endpoints: upload, relay, probe, health
rocket-sim/               B's secret program, a stand-in (a real B keeps this private)
cli/                      demo, the one CLI both companies use
examples/                 A's confidential design (falcon-hobby.json)
caution.hcl               the enclave config: both hash pins, one port, no egress  (A reviews)
Containerfile             reproducible build of the broker, and nothing else
Makefile                  make sim, make test, make test-jail
scripts/qemu-jail-test/   runs the jail tests on the pinned enclave kernel under QEMU

Quickstart: the demo on Nitro

Tested end to end, both sides, on a Caution staging environment on AWS Nitro. make and demo need x86_64 Linux (on macOS, an OrbStack ubuntu-amd64 VM). B needs a Caution account; both need docker for caution verify.

0 · Both: get the CLI.

git clone https://git.caution.co/public/demo-conf-processing.git && cd demo-conf-processing
cargo build --release -p cli && export PATH=$PWD/target/release:$PATH

1 · A: make a token and send B only the printed hash.

demo token   # writes a.token, prints its SHA-256

2 · B: pin both hashes and deploy from a deploy branch.

make sim                     # builds rocket-sim, prints its SHA-256
git switch -c deploy         # put both hashes in caution.hcl (the REPLACE_WITH_... args)
caution login --username <you> && caution init
git add caution.hcl .caution/deployment.json && git commit -m "Pin rocket-sim and A's token"
git push caution deploy:main # ~7 min; ends with "Application: http://<app-ip>"

3 · B: publish the deploy commit to a repo A can read, then send A the repo and app URL.

git push <b-repo> deploy

4 · A: review and verify. A clones B's repo inside its own folder, so the token is at ../a.token.

git clone -b deploy <b-repo> company-b-app && cd company-b-app
less broker/src/jail.rs broker/src/seccomp.rs caution.hcl
sha256sum ../a.token   # must equal --client-token-sha256 in caution.hcl
APP=http://<app-ip>
caution verify --attestation-url "$APP/attestation"   # PASSED
d() { demo "$@" --enclave "$APP" --pcrs .caution/trusted_hashes.json --token-file ../a.token; }

5 · B: load the secret simulator.

caution verify && APP=http://<app-ip>
d() { demo "$@" --enclave "$APP" --pcrs .caution/trusted_hashes.json; }
d push target/x86_64-unknown-linux-musl/release/rocket-sim   # loaded

6 · A: run the probe.

d probe   # 11 lines, all BLOCKED

7 · A: run the simulation.

d design examples/falcon-hobby.json                # d1
d launch d1 --wind 5 --out out/calm                # Nominal: apogee 1662 m
d launch d1 --wind 15 --angle 80 --out out/gusty   # Nominal: apogee 934 m

8 · B: try to look.

demo token --out b.token && d design examples/falcon-hobby.json --token-file b.token   # 401
curl -s "$APP/app/designs"                                                             # 403 e2e_required

9 · Clean up.

d wipe                 # A: the simulator forgets every design and launch
caution apps destroy   # B: stops the enclave

One program at a time: a push while it runs gets 409. If it exits or crashes, B pushes the same binary again (no redeploy) and A re-sends its designs. A new binary means a new hash and a redeploy. Never add --dev, an egress block, or an ingress rule for port 9000 to caution.hcl.

Tests

make test        # unit and integration tests
make test-jail   # the jail on the pinned Nitro kernel under QEMU (needs qemu and docker)

Limits

  • The simulator controls the size and timing of its responses, which the host can see: a slow covert channel. Padding would close most of it.
  • The jail still trusts the enclave kernel. For production, run the simulator under gVisor and switch the seccomp denylist to an allowlist.
  • One customer per enclave, and the simulator must accept a handed-in socket (--listen-fd).