Fetch, verify, and integrate CVM attestation into your workflow — end-to-end with working code
Verify that your CVM runs unmodified code on genuine TEE hardware, from fetching the attestation quote to integrating verification into your CI/CD pipeline. This guide ties together the attestation workflow end-to-end with working code examples.If you’re new to attestation, start with the Quickstart to understand the basics through the dashboard. This guide assumes you want programmatic verification.
Every CVM attestation verification follows three steps: get a quote from your running CVM, verify the quote’s hardware signature, and check that the measurements match your expected application. The entire process runs in seconds from anywhere outside the CVM.
Your CVM must expose attestation endpoints. If you haven’t set this up yet, see Get Attestation for the dstack SDK setup.Fetch the quote with a fresh challenge nonce to prevent replay attacks.
import crypto from 'crypto';const CVM_URL = 'https://your-app.example.com';// Generate a fresh 32-byte nonceconst nonce = crypto.randomBytes(32).toString('hex');// Fetch attestation with nonce as reportDataconst attestResponse = await fetch(`${CVM_URL}/attestation?reportData=${nonce}`);const attestData = await attestResponse.json();// Fetch application info for compose verificationconst infoResponse = await fetch(`${CVM_URL}/info`);const appInfo = await infoResponse.json();console.log('Quote length:', attestData.quote.length);console.log('Event log events:', JSON.parse(attestData.event_log).length);
Always generate a fresh nonce per verification request. Without it, an attacker could replay an old valid quote from compromised hardware.
The TDX quote is signed by Intel hardware. Verify this signature to confirm the quote came from a genuine TEE. You have two options: use Phala’s verification API for convenience, or verify locally for trustless verification.
Hardware verification proves the TEE is genuine. Now verify that your specific application is running inside it. The compose-hash in RTMR3 is a SHA256 hash of your entire Docker Compose configuration.
import { createHash } from 'crypto';// Calculate the compose hash from the app infoconst appCompose = appInfo.tcb_info.app_compose;const calculatedHash = createHash('sha256') .update(appCompose) .digest('hex');// Extract the attested hash from the RTMR3 event logconst events = JSON.parse(attestData.event_log);const composeEvent = events.find( (e: { event: string }) => e.event === 'compose-hash');const attestedHash = composeEvent.event_payload;if (calculatedHash !== attestedHash) { throw new Error( `Compose hash mismatch: expected ${calculatedHash}, got ${attestedHash}` );}console.log('Application code: verified');console.log('Compose hash:', calculatedHash);
Confirm that the quote contains your original nonce. This proves the attestation was freshly generated for your request.
// The reportData field in the quote should start with your nonceconst reportData = attestData.report_data;if (!reportData.startsWith(nonce)) { throw new Error('Nonce mismatch: possible replay attack');}console.log('Freshness: verified');
Attestation verification fits naturally into deployment pipelines. Run it after every deployment to confirm your CVM booted correctly with the expected code.
For production systems, run verification checks on a schedule. Here’s a lightweight monitoring approach:
import timeimport logginglogging.basicConfig(level=logging.INFO)logger = logging.getLogger("attestation-monitor")CVM_URLS = [ "https://app1.example.com", "https://app2.example.com",]CHECK_INTERVAL = 3600 # 1 hourwhile True: for url in CVM_URLS: try: result = verify_cvm(url) if result: logger.info(f"PASS: {url}") else: logger.error(f"FAIL: {url}") # Send alert to your monitoring system except Exception as e: logger.error(f"ERROR: {url} - {e}") time.sleep(CHECK_INTERVAL)
Attestation verification must always run outside the CVM. Verification running inside the CVM provides no security guarantees because a compromised CVM could fake its own results.
Here’s a quick reference for what you’re verifying at each step and what attack it prevents.
Check
What it proves
Attack prevented
Hardware signature
Quote came from genuine Intel TDX
Fake TEE simulation
Compose hash
Your exact Docker images are running
Code substitution
Nonce freshness
Quote was generated for this request
Replay of old quotes
reportData binding
Custom data is attested by hardware
Data tampering
For advanced verification including RTMR3 event log replay, Docker digest pinning, on-chain governance, and source code provenance, see the Complete Chain of Trust.