What we found in TeeChat’s seal-sync protocol — and how we closed it
On August 30, 2026, an internal security review found a critical flaw in the implementation of the seal-sync protocol, the administrative protocol TeeChat uses to move a serving TLS key between blue/green trusted environments.
We found this issue before enabling payments and beginning to promote the product.
This post is the closure announcement. We contained the reachable ports, found no evidence of a malicious key export or user-data leak, deployed the fixed version, replaced the assumed-compromised serving keys, and revoked the associated public certificates.
What the seal-sync protocol does
All of TeeChat’s internal and external TLS connections use TLS 1.3, for the strongest practical transport guarantee. Every private key is generated inside a confidential container (a key ceremony) and sealed to disk so that only that same container can open it. During a service upgrade, we use the seal-sync protocol to encrypt and transfer the private key between attested service components. The private key never leaves the confidential container in plaintext.
The flaw
The intended design called for attested TLS 1.3. The implementation did not fully satisfy that contract:
- the administrative TLS listener did not require a client certificate;
- requester measurements could be accepted without complete AMD SNP or Intel DCAP signature, chain, TCB and debug-state verification;
- a requester could supply the endpoint used for a secondary challenge;
- development authentication remained reachable in the gateway seal tool;
- some QEMU forwards and SGX listeners bound to all interfaces instead of loopback;
- the exported private key was plaintext inside the TLS application response instead of being additionally encrypted to a key proven to belong to the requesting TEE.
An attacker would have needed to reach a seal-sync listener and pass or bypass these checks. If successful, the attacker could receive the serving TLS private key.
If a key were stolen, what an attacker could and could not see
Even if the certificate private key were stolen, an attacker could not decrypt previously recorded TeeChat traffic. The affected services require TLS 1.3, whose ephemeral key exchange provides forward secrecy.
A more serious possible outcome would be an attacker impersonating the identity and establishing a connection. The attacker would still need control over routing, DNS, a proxy, an upstream host, or a client endpoint. A successfully impersonated OpenAPI endpoint could then see new requests and credentials presented to that endpoint.
We found no evidence that this happened.
How we found it
The finding came from TeeChat’s internal security review, not from a customer report or an external disclosure.
We compared the written protocol contract with the actual Rust implementations, deployment templates and running network surfaces. Read-only identity requests confirmed that production OpenAPI and gateway seal-sync listeners were reachable publicly. Git history then showed that an empty QEMU host address had created all-interface forwards. The first affected OpenAPI configuration entered the repository on July 22; gateway followed on July 26; SGX lab listeners followed on July 29.
The public-bind source paths were corrected and host firewall containment was applied on August 30. These dates bound the possible exposure period.
What the retained logs show
The retained SGX lab logs contain:
- 16 successful exporter-side records;
- 16 matching importer records showing the key was sealed and persisted;
- 2 denied attestation attempts associated with deployment measurement changes;
- 25 already-aligned checks that did not export a key;
- 0 confirmed malicious exports.
The successful records correlate with our blue/green lab migrations and are classified as legitimate with moderate confidence.
Current and immediately previous retained production OpenAPI and gateway logs contain zero successful export records. That retention does not cover the entire possible exposure period.
The old audit format also omitted reliable timestamps, source addresses and a cryptographically authenticated requester key.
Conclusion
Combined with the additional controls a successful attack would still need — routing, DNS, a proxy, an upstream host, or a client endpoint — our conclusion is: no confirmed attack or leak occurred, and the security of user data was not affected. Even so, we are publishing this announcement to stay transparent on security that matters. This will also be the standard we follow going forward.
Immediate containment
We:
- blocked non-loopback ingress to every identified seal-sync port;
- changed future QEMU and SGX launches to bind seal-sync on loopback;
- externally checked the OpenAPI, gateway and SGX lab port matrix from an independent host;
- kept ceremony exporters parked outside witnessed migration windows;
- added regression tests that reject wildcard seal-sync forwards.
These controls closed the public network path. Containment is not the same as correcting the protocol, so we then deployed the fixed version and replaced the serving keys.
Permanent fix
The fixed version now:
- verifies complete AMD SNP and Intel DCAP evidence and derives the measurement from that evidence;
- rejects debug or unacceptable TCB states;
- binds a server-generated, single-use nonce, requester key, destination and export operation into the quote;
- generates an ephemeral X25519 key inside the requesting TEE;
- encrypts the export to that attested key using HPKE, so a private key is never plaintext in the wire response;
- uses server-owned peer policy instead of requester-selected challenge destinations;
- makes empty allowlists, development attestors, default secrets and public binds fatal in production;
- fails closed if the durable pre-export or completion audit record cannot be written.
Replacing the assumed-compromised keys
We treated the existing serving keys as assumed compromised even though we found no confirmed export.
We minted new identities in measured ceremony environments, published the new SPKIs, migrated OpenAPI and gateway through the fixed version, retired the old SPKIs, and verified the resulting production and lab environments (external port checks, attestation checks, and product regression).
A stolen private key can still be used with a not-yet-expired public certificate. We therefore treated the associated certificates as assumed compromised as well and revoked them at the issuing certificate authority, so relying parties that check revocation will reject the old leaves.
Revision log
- Link the public seal-sync protocol and state that the private key never leaves the confidential container in plaintext.
- Note that associated certificates were assumed compromised and revoked at the CA.