DevProof
Proving that developers can't rug users. Not security auditing—trust model verification.
What is DevProof?
DevProof is about proving absence of privileged access, not finding vulnerabilities. Think warrant canary, not intrusion detection.
TEE apps make strong claims: "your data never leaves the enclave," "the operator can't see your messages." These claims are often partially true. DevProof finds the partial parts.
The core insight: TEE protects against the cloud provider. It does NOT protect against the operator. The operator controls which code runs, which environment variables are set, when to upgrade. Users verify attestation and think they're safe—but they're trusting that the operator configured things correctly.
ERC-733 Security Stages
ERC-733 defines a progression from prototype to trustless:
| Stage | Name | Definition |
|---|---|---|
| 0 | Prototype/Ruggable | TEE improves security but developer remains single point of failure |
| 1 | Dev-Proof | Developer cannot unilaterally alter, censor, or exfiltrate without notice period |
| 2 | Decentralized TEE | Multiple enclaves/vendors, no single party controls |
| 3 | Trustless TEE | ZK hybrids, multi-vendor cross-attestation |
Stage 1 is the goal. Every project can reasonably achieve it with attention to detail.
Stage 1 Checklist
From ERC-733 (fail any = Stage 0):
- Enclaves attested on-chain
- Code auditable (open source or formal verification)
- Community can reproducibly compute code measurement
- Developer has no access to application secrets
- Well-defined upgrade process with notice period
- No dependency on centralized infrastructure except TEE vendors
- No backdoor or debug paths
See framework/STAGE-1-CHECKLIST.md for detailed verification steps.
Case Studies
| Project | Stage | Key Issue |
|---|---|---|
| hermes | 0 | Pha KMS (no public upgrade log), mutable image tags |
| near-private-chat | 0 | Backend routing unverified, 56 compose hashes authorized |
| near-ai-private-inference | 0 | Inner compose not in RTMR3, model weights unverified, operator log access |
| primus | 0 | Closed-source core (libpado.so), binary blobs |
| talos | ~1 | Reproducible builds, but enclave ID verification gap |
| tee-totalled | 0 | LLM_BASE_URL operator-configurable (exfiltration) |
| tokscope-xordi | 0 | v1.1.2: images public, repro builds improved; still ${VAR} image refs, Pha KMS |
| confer.to | 0 | Analysis in progress |
| venice-private-inference | 0 | ECIES wire protocol works; veniceai/skills misnames it "HPKE/Noise", omits every TDX-verification step |
| phala-private-ai-verifier | 0 | Attestation-only SDK; no E2EE code, signing_public_key never read, "verified" is not confidentiality |
| tinfoil-confidential-inference | ~1 | Closes the Phala/NEAR compose-hash gap (config sha256 in launch-measured cmdline). Model weights are dm-verity-anchored with HF commit pinned in the attested config — runtime tampering produces EIO, no HF-by-name fetch like NEAR AI. Per-model enclaves fully attested; router has 2 externally-sourced slots (DOMAIN, USAGE_REPORTER_SECRET) — code-trace-shown to be off the prompt path |
| xordi-toy-example | 1 | Reference implementation with Base KMS |
| trustedrouter-confidential-router | ~1 | First GCP Confidential Space study. Clean chain (Google-signed EAT JWT, eat_nonce[0]==SHA-256(TLS leaf), digest==published) and routing is locked/attested (hardcoded upstream URLs, control plane can't inject). Top gap G6: shared ACME TLS private key cached in operator-readable GCS (CMEK not image-bound) → operator can MITM with the genuine cert + relayed attestation, which per-session verification cannot catch. Prompts not persisted; upgrades mooted by verify-each-session |
Common Failures
The same patterns appear in every Stage 0 app:
- Configurable URLs -
API_URL=${API_URL}instead of hardcoded - Pha KMS - No public upgrade log (can't answer "what ran last week?")
- Mutable image tags -
image:v1.0instead ofimage@sha256:... - "Known issue" bypasses - Hash mismatch accepted with comment
- Dev fallbacks -
if DEV_MODE: return hardcoded_key
See LEARNINGS.md for detailed patterns.
Framework
- DOMAIN-BINDING-GAP.md - Custom domain routing gap (affects all dstack apps)
- APP-MEASUREMENT-HOOK.md - Cross-vendor confidential-inference gap: no app-facing way to bind code/model into the quote (model substitution + prompt exfil)
- STAGE-1-CHECKLIST.md - How to verify Stage 1
- templates/DEVPROOF-REPORT.md - Gap analysis template
- templates/DEPLOYMENTS.md - Upgrade history template
- templates/RELEASE-CHECKLIST.md - Deploy process
Tools
Verification Scripts
- verify-compose-hash.py - Verify compose hash from 8090 endpoint
./tools/verify-compose-hash.py <app-id> [cluster] # Example: ./tools/verify-compose-hash.py f44389ef4e953f3c53847cc86b1aedc763978e83 dstack-pha-prod9
External Tools
- Trust Center UI: trust.phala.com - Visual attestation verification
- @phala/dstack-verifier - Full attestation verification library
- dstack-mr - OS measurement computation
- dcap-qvl - TDX quote verification
Data Sources (for third-party auditing)
- 8090 endpoint:
https://<app-id>-8090.<cluster>.phala.network/- TCB info, app_compose, event log - Note:
phala cvms attestationonly works for apps you own - useless for third-party auditing
Claude Code Skills
- dstack-audit-plugin - Automated audit skill
References
- ERC-733 Summary - TEE+EVM security stages
- Disintermediation - The github-zktls framing
The Goal
"Not merely that the developer cannot misbehave, but that this is provable to users before they interact." — GitHub as a Trusted Execution Environment
DevProof is complete when users can verify, before trusting an app with sensitive data, that the developer is as constrained as anyone else.