CVE-2026-22696: Fetching Collateral is not Enough
TEE Security+1March 13, 2026

CVE-2026-22696: Fetching Collateral is not Enough

By Rahul Saxena (@saxenism)

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

GHSA Advisory

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-qvl fetched 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-qvl 0.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

DateEvent
January 6, 2026Vulnerability reported to Phala Network
January 24, 2026Advisory published as GHSA-796p-j2gh-9m2q
January 26, 2026CVE record published as CVE-2026-22696
January 2026Patch released in dcap-qvl 0.3.9

Affected Packages

PackageEcosystemAffected VersionsPatched
dcap-qvlcargo< 0.3.90.3.9
dcap-qvlpip< 0.3.90.3.9
@phala/dcap-qvlnpm<= 0.3.00.3.9
@phala/dcap-qvl-nodenpm<= 0.3.3Migrate to @phala/dcap-qvl
@phala/dcap-qvl-webnpm<= 0.3.3Migrate 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

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.