Finding 2/6: Intel Said OutOfDate. dstack Said OK.
Missing TCB Status Enforcement in dstack's RA-TLS Attestation Library
Severity: High
Affected components: dstack RA-TLS attestation verification (ra-tls crate), with downstream exposure in KMS and app authorization flows
Repository: github.com/Dstack-TEE/dstack
Attestation tells you whether code ran inside a genuine TEE. TCB status tells you whether that TEE is still safe to trust. This write-up covers a missing enforcement flaw in dstack's RA-TLS library where the second question was not enforced.
The issue was identified by Bluethroat Labs and responsibly disclosed to Phala Network in January 2026.

Executive Summary
- dstack's
validate_tcb()function verified hardware attributes but ignored Intel's TCB status assessment entirely. dcap-qvlalready returnedstatusandadvisory_ids, but the shared RA-TLS verifier did not enforce either field.- Quotes from degraded platforms such as
OutOfDate,ConfigurationNeeded, orRevokedcould still pass RA-TLS verification as long as they remained cryptographically valid. - KMS-specific authorization enforced
UpToDate, but the stock app authorization path did not apply the same TCB gate. - This is High severity because attestation sits on authorization-critical paths, and the library default treated Intel's security verdict as non-blocking.
Background
Intel DCAP quote verification answers two different questions.
First: is the quote authentic?
Second: is the attesting platform still acceptable to trust under Intel's current TCB policy?
That second answer appears as a TCB status such as UpToDate, OutOfDate, ConfigurationNeeded, SWHardeningNeeded, or Revoked. A quote can be genuine and still come from a platform Intel considers degraded. That is why status enforcement matters.
dstack's ra-tls crate is the shared attestation verification layer used in RA-TLS certificate and quote validation flows across the dstack stack. If this layer treats TCB status as informational, downstream consumers inherit that footgun by default.
Vulnerability Details
The validate_tcb() function in ra-tls/src/attestation.rs is where TCB assessment appears to happen. It receives a VerifiedReport containing both the hardware report and Intel's TCB verdict:
// dcap-qvl/src/verify.rs
pub struct VerifiedReport {
pub status: String, // TCB status — NOT CHECKED
pub advisory_ids: Vec<String>, // Security advisories — NOT CHECKED
pub report: Report,
pub ppid: Vec<u8>,
}The status field contains Intel's TCB assessment. The advisory_ids field contains Intel Security Advisory IDs associated with the matched TCB level. Both are populated by the upstream dcap-qvl verification library. Neither is inspected by validate_tcb():
// ra-tls/src/attestation.rs, lines 352-382
pub fn validate_tcb(report: &VerifiedReport) -> Result<()> {
fn validate_td10(report: &TDReport10) -> Result<()> {
let is_debug = report.td_attributes[0] & 0x01 != 0;
if is_debug {
bail!("Debug mode is not allowed");
}
if report.mr_signer_seam != [0u8; 48] {
bail!("Invalid mr signer seam");
}
Ok(())
}
fn validate_td15(report: &TDReport15) -> Result<()> {
if report.mr_service_td != [0u8; 48] {
bail!("Invalid mr service td");
}
validate_td10(&report.base)
}
fn validate_sgx(report: &EnclaveReport) -> Result<()> {
let is_debug = report.attributes[0] & 0x02 != 0;
if is_debug {
bail!("Debug mode is not allowed");
}
Ok(())
}
match &report.report {
Report::TD15(report) => validate_td15(report),
Report::TD10(report) => validate_td10(report),
Report::SgxEnclave(report) => validate_sgx(report),
}
}The function checks debug mode and selected report attributes. It does not read report.status or report.advisory_ids. A quote from a platform Intel has marked Revoked passes this function the same way a quote from an UpToDate platform does, as long as the quote is otherwise cryptographically valid and the checked attributes pass.
This function is called in the main verification path (attestation.rs, line 340), meaning every quote verified through the RA-TLS library inherits this gap:
// ra-tls/src/attestation.rs, line 340
validate_tcb(&report)?;
Ok(VerifiedAttestation {
quote: self.quote,
raw_event_log: self.raw_event_log,
event_log: self.event_log,
report,
})This is not because status is unavailable. dcap-qvl computes it directly from Intel's tcb_levels and returns it in VerifiedReport. RA-TLS simply does not turn that verdict into a fail-closed policy decision.
The Asymmetric Enforcement Problem
The TCB status does flow downstream to the smart contract authorization layer. The KMS passes it through BootInfo:
// kms/src/main_service.rs, line 459
tcb_status: att.report.status.clone(),
advisory_ids: att.report.advisory_ids.clone(),The smart contract then enforces TCB status, but only for KMS nodes:
// DstackKms.sol, lines 208-217
function isKmsAllowed(
AppBootInfo calldata bootInfo
) external view returns (bool isAllowed, string memory reason) {
if (
keccak256(abi.encodePacked(bootInfo.tcbStatus)) !=
keccak256(abi.encodePacked("UpToDate"))
) {
return (false, "TCB status is not up to date");
}
// ...
}For applications, DstackApp.sol checks compose hashes and device allowlists but does not check tcbStatus. The result is an asymmetric model:
- RA-TLS verification does not fail closed on degraded TCB states.
- KMS authorization adds its own
UpToDaterequirement. - The stock app authorization path shown here does not.
Representative Attack Scenario
An attacker controls a platform Intel has already downgraded to OutOfDate or another degraded TCB state due to known security issues.
The attacker generates a DCAP quote from this platform. The quote is still cryptographically valid: Intel's PCK chain validates, the report signature checks out, and dcap-qvl returns a VerifiedReport. Intel's TCB recovery windows mean such quotes can remain usable for months while operators are expected to update.
The attacker then submits this quote to a dstack application using RA-TLS. The verification path looks like this:
Attacker controls degraded platform
|
v
Generates cryptographically valid DCAP quote
|
v
Submits quote to dstack application via RA-TLS
|
v
dcap-qvl verifies quote cryptography ✓ Returns status: "OutOfDate"
|
v
validate_tcb() checks:
Debug mode disabled ✓
mr_signer_seam is zero ✓
TCB status "OutOfDate" — NOT CHECKED ✗
Advisory IDs (INTEL-SA-...) — NOT CHECKED ✗
|
v
Quote accepted. Application grants authorization.
|
v
Authorization succeeds based on a platform Intel has already flagged
as needing security action.This matters because the gap sits on an authorization path, not an observability path. Even though KMS adds an extra UpToDate check, the shared verifier does not, and the stock app path shown here lacks the same guard. A developer integrating validate_tcb() would reasonably assume TCB validation was already complete. It was not.
Severity Classification
We reported this as High severity.
This is not a cosmetic validation gap. It is a trust-decision bug in a shared attestation verifier. Intel's security verdict was already available, but the library treated it as metadata instead of policy. That meant a cryptographically valid quote from a degraded platform could still clear RA-TLS verification and reach downstream authorization logic.
The High rating is justified by three things:
- attestation is used on authorization-critical paths
- degraded quotes can remain usable for extended recovery windows
- the library API and documentation create the impression that TCB validation is already handled
Fix
The fix should add explicit TCB status enforcement to validate_tcb(), rejecting degraded platforms by default. If a deployment wants to allow something like SWHardeningNeeded, that should be an explicit policy choice, not the silent default. The app authorization path should also enforce the same TCB policy already applied to KMS nodes.
Key Takeaway for Attestation Implementers
Cryptographic validity and security posture are independent properties. A quote can be authentic and still come from a platform Intel no longer wants you to trust. If your verifier checks the signature but ignores the status, you are enforcing authenticity without enforcing security.
References
- Affected code at time of disclosure (commit
09d10bc, Jan 4 2026):ra-tls/src/attestation.rs—validate_tcb()functionkms/auth-eth/contracts/DstackKms.sol—isKmsAllowed()kms/auth-eth/contracts/DstackApp.sol— app authorization path without TCB status enforcement
dcap-qvl/src/verify.rs—VerifiedReportstruct with unusedstatusandadvisory_idsfields
This vulnerability was discovered by Rahul Saxena of Bluethroat Labs during a security assessment of the dstack ecosystem. Responsible disclosure was coordinated with Phala Network.
For a public timeline of the disclosure process, see this thread.
This is the second in a series covering the six vulnerabilities identified during this assessment. The first write-up covered CVE-2026-22696: Missing QE Identity Verification.
