CVE-2026-22696: Fetching Collateral is not Enough
CVE: CVE-2026-22696
Advisory: GHSA-796p-j2gh-9m2q
Severity: Critical
Patched version: 0.3.9 (dcap-qvl / @phala/dcap-qvl)

Remote attestation only works if every trust decision in the chain is verified correctly. This write-up covers CVE-2026-22696, a missing verification flaw in dcap-qvl.
It focuses on technical behavior and public advisory records.
The issue was identified by Rahul Saxena from Bluethroat Labs and responsibly disclosed to Phala Network in January 2026.
Executive Summary
dcap-qvlfetched QE Identity collateral but did not validate its certificate chain, signature, or policy constraints.- As a result, quotes from outdated or non-compliant Quoting Enclave states could be accepted when policy checks should fail closed.
- The issue affected multiple package distributions and was fixed in
dcap-qvl0.3.9.
Background
Intel's DCAP (Data Center Attestation Primitives) is the standard mechanism for verifying SGX and TDX quotes without relying on Intel's legacy EPID attestation service. A DCAP quote verifier must validate several pieces of collateral fetched from a Provisioning Certificate Caching Service (PCCS):
- PCK Certificate Chain — binds the quote's signing key to Intel's root CA
- TCB Info — maps platform firmware/microcode versions to a security status
- CRLs — revocation lists for compromised certificates
- QE Identity — Intel-signed policy document specifying the expected identity of the Quoting Enclave (MRSIGNER, ISVPRODID, ISVSVN, attribute masks)
QE Identity verification answers a specific question: was this quote produced by a legitimate, up-to-date Intel Quoting Enclave? Without it, a verifier cannot enforce Intel's QE identity policy constraints.
Phala Network's dcap-qvl is a Rust DCAP quote verification library used across the dstack ecosystem for TEE attestation. It ships as a Rust crate, npm package, and Python package, and underpins attestation verification for Phala's KMS, RA-TLS certificate issuance, and trust-center verification services.
Vulnerability Details (Affected Versions)
In affected versions (< 0.3.9 for dcap-qvl package lines), the library fetched QE Identity collateral (the signed JSON document, its ECDSA signature, and the issuer certificate chain) but did not verify any of it.
In get_collateral(), the affected code path fetched and parsed QE Identity from PCCS:
// dcap-qvl/src/collateral.rs
let response = client.get(endpoints.url_qe_identity()).send().await?;
qe_identity_issuer_chain = get_header(&response, "SGX-Enclave-Identity-Issuer-Chain")?;
raw_qe_identity = response.text().await?;
// Parse and extract signature
let qe_identity_resp: QeIdentityResponse =
serde_json::from_str(&raw_qe_identity).context("QE Identity should be valid JSON")?;
let qe_identity = qe_identity_resp.enclave_identity.to_string();
let qe_identity_signature = hex::decode(&qe_identity_resp.signature)
.ok()
.context("QE Identity signature must be valid hex")?;All three fields (qe_identity, qe_identity_signature, qe_identity_issuer_chain) were stored in QuoteCollateralV3. The affected verify() path did not use them.
The asymmetry with TCB Info makes it clear this is incomplete implementation, not a design choice. TCB Info gets the full treatment:
// dcap-qvl/src/verify.rs — TCB Info: fully verified
let tcb_certs = extract_certs(collateral.tcb_info_issuer_chain.as_bytes())?;
let [tcb_leaf, tcb_chain @ ..] = &tcb_certs[..] else {
bail!("Certificate chain is too short in quote_collateral");
};
let tcb_leaf_cert = webpki::EndEntityCert::try_from(tcb_leaf)
.context("Failed to parse leaf certificate in quote_collateral")?;
verify_certificate_chain(&tcb_leaf_cert, tcb_chain, now, &crls, trust_anchor.clone())?;
let asn1_signature = encode_as_der(&collateral.tcb_info_signature)?;
if tcb_leaf_cert
.verify_signature(
webpki::ring::ECDSA_P256_SHA256,
collateral.tcb_info.as_bytes(),
&asn1_signature,
)
.is_err()
{
return Err(anyhow!("Signature is invalid for tcb_info in quote_collateral"));
}QE Identity required the same verification pattern: validate the issuer certificate chain against Intel's root CA, verify the ECDSA signature over the QE Identity JSON, then enforce policy constraints (MRSIGNER, ISVPRODID, ISVSVN, miscselect/attributes masks) against the QE Report embedded in the quote. None of these steps happened in affected versions.
Missing Verification Steps in Affected Versions
The missing checks were distinct and independently important:
1. Certificate chain validation — not performed. The qe_identity_issuer_chain was fetched but never parsed or validated against Intel's root CA.
2. Signature verification — not performed. The qe_identity_signature was hex-decoded and stored, but never checked against the signing certificate.
3. Policy enforcement — not performed. Even assuming authentic QE Identity data, the verifier never compared QE Report fields against policy. Specifically:
- MRSIGNER was not checked against Intel's expected value. The verifier could not confirm the Quoting Enclave was built by Intel.
- ISVSVN was not compared against the minimum version from QE Identity TCB levels. Quotes from QE versions with known vulnerabilities could be accepted.
- ISVPRODID was not verified. The QE product identity was not confirmed.
- MISCSELECT and ATTRIBUTES masks were not applied.
Representative Attack Scenario
An attacker with access to a platform running an outdated Quoting Enclave (one with known security vulnerabilities and a lower ISVSVN) could generate a DCAP quote. The quote remained cryptographically valid: the PCK certificate chain traced back to Intel's root CA, the QE report signature checked out against the PCK public key, and the attestation key binding was intact.
In affected versions, the verifier could accept the quote. It had no mechanism to reject it based on QE version because QE Identity policy enforcement was absent.
This mattered because Intel periodically updates the Quoting Enclave to address security vulnerabilities. When Intel bumps the QE's ISVSVN, it publishes updated QE Identity collateral specifying the new minimum version. A verifier that enforces QE Identity policy would reject quotes from the old QE. Affected versions did not.
The attack surface scaled with adoption: every deployment using affected dcap-qvl versions for quote verification inherited this gap. The library shipped across three package ecosystems (Rust, npm, Python).
Attacker controls platform with outdated QE (known CVEs, lower ISVSVN)
|
v
Generates cryptographically valid DCAP quote
|
v
Submits quote to any service using dcap-qvl for verification
|
v
PCK chain validates ✓ QE report signature validates ✓ TCB Info checks pass ✓
|
v
QE Identity signature — not checked ✗
QE MRSIGNER — not checked ✗
QE ISVSVN vs minimum — not checked ✗
|
v
Quote accepted. Verifier cannot distinguish this from a quote
produced by Intel's current, fully-patched Quoting Enclave.Scope of the gap. Not all verification was absent in affected versions. The verifier validated Intel-rooted certificate chains for attestation collateral, enforced CRL-based revocation checks, verified the QE report signature and quote binding integrity, and rejected debug-mode reports. These controls established collateral authenticity and quote integrity, but they did not enforce Quoting Enclave identity/policy compliance (for example, MRSIGNER/ISVPRODID/ISVSVN and related mask checks). QE Identity verification was the missing enforcement layer that closed this gap.
Severity Classification
We initially reported this as High severity. The published advisory classifies it as Critical in GHSA-796p-j2gh-9m2q, citing bypass of the attestation trust model.
Fix
The patch in version 0.3.9 implements the three missing verification steps: certificate chain validation for the QE Identity issuer chain, ECDSA signature verification over the QE Identity JSON, and policy enforcement for MRSIGNER, ISVPRODID, and ISVSVN against the QE Report.
Timeline
| Date | Event |
|---|---|
| January 6, 2026 | Vulnerability reported to Phala Network |
| January 24, 2026 | Advisory published as GHSA-796p-j2gh-9m2q |
| January 26, 2026 | CVE record published as CVE-2026-22696 |
| January 2026 | Patch released in dcap-qvl 0.3.9 |
Affected Packages
| Package | Ecosystem | Affected Versions | Patched |
|---|---|---|---|
dcap-qvl | cargo | < 0.3.9 | 0.3.9 |
dcap-qvl | pip | < 0.3.9 | 0.3.9 |
@phala/dcap-qvl | npm | <= 0.3.0 | 0.3.9 |
@phala/dcap-qvl-node | npm | <= 0.3.3 | Migrate to @phala/dcap-qvl |
@phala/dcap-qvl-web | npm | <= 0.3.3 | Migrate to @phala/dcap-qvl |
If you are using any affected version, upgrade to 0.3.9 immediately. There are no workarounds.
Key Takeaway for Attestation Implementers
Fetching collateral is not enough. You must verify every signed policy artifact used for trust decisions and enforce those policy constraints in the final acceptance logic. Partial verification is equivalent to broken verification.
References
- GHSA: github.com/Phala-Network/dcap-qvl/security/advisories/GHSA-796p-j2gh-9m2q
- CVE: cve.org/CVERecord?id=CVE-2026-22696
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 where Bluethroat added another engineering asset to the process, Tanmay who worked with the Phala for over a month for a thorough remediation.
For a public timeline of the disclosure process, see: x.com/saxenism/status/2021943382155899351.
This is the first in a series covering the six vulnerabilities identified during this assessment.
