quarkusio/quarkus · critical · SpiffeConnectionException

X.509-SVID proto SPIFFE ID does not match the leaf certifica

Error message

X.509-SVID proto SPIFFE ID does not match the leaf certificate URI SAN; proto: ${protoSpiffeId}, SAN: ${sanSpiffeId}

What it means

The SPIFFE ID from the protobuf message does not match the URI SAN (spiffe://...) embedded in the leaf certificate the agent returned. SPIFFE security depends on this consistency: the workload identity claimed in the response must be the identity cryptographically bound to the certificate. A mismatch means the response is untrustworthy or misbuilt.

Source

Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java:310

        if (svid.getX509Svid().isEmpty()) {
            throw new SpiffeConnectionException("X.509-SVID response from SPIRE agent has empty certificate chain");
        }
        if (svid.getX509SvidKey().isEmpty()) {
            throw new SpiffeConnectionException("X.509-SVID response from SPIRE agent has empty private key");
        }
        if (svid.getBundle().isEmpty()) {
            throw new SpiffeConnectionException("X.509-SVID response from SPIRE agent has empty trust bundle");
        }

        List<X509Certificate> certChain = parseCertificates(svid.getX509Svid().toByteArray(), "certificate chain");
        if (certChain.isEmpty()) {
            throw new SpiffeConnectionException("X.509-SVID certificate chain is empty");
        }

        X509Certificate leaf = certChain.get(0);
        String sanSpiffeId = SpiffeValidator.validateLeaf(leaf);
        if (!protoSpiffeId.equals(sanSpiffeId)) {
            throw new SpiffeConnectionException(
                    "X.509-SVID proto SPIFFE ID does not match the leaf certificate URI SAN; proto: "
                            + protoSpiffeId + ", SAN: " + sanSpiffeId);
        }
        for (int i = 1; i < certChain.size(); i++) {
            SpiffeValidator.validateIntermediate(certChain.get(i));
        }

        String keyAlgorithm = leaf.getPublicKey().getAlgorithm();
        PrivateKey privateKey;
        try {
            privateKey = KeyFactory.getInstance(keyAlgorithm)
                    .generatePrivate(new PKCS8EncodedKeySpec(svid.getX509SvidKey().toByteArray()));
        } catch (Exception e) {
            throw new SpiffeConnectionException("X.509-SVID response from SPIRE agent contains an invalid private key", e);
        }

        List<X509Certificate> trustBundle = parseCertificates(svid.getBundle().toByteArray(), "trust bundle");

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure the Workload API socket is the genuine agent unix socket (check for rogue listeners on the path).
  2. Recreate the SPIRE registration entry so the spiffeID matches the identity actually issued.
  3. Restart the agent and re-request the certificate; check agent/server versions.
  4. Audit the SPIRE server entry spiffeID and trust domain for typos or stale values.

Example fix

// before: entry spiffeID spiffe://old.example.org/ns/prod/sa/app, cert issued for spiffe://example.org/...
// after: align entry with issued identity
// spire-server entry update -entryID <id> -spiffeID spiffe://example.org/ns/prod/sa/app
Defensive patterns

Strategy: try-catch

Validate before calling

// after fetching, compare proto id to cert SAN yourself (fail closed on mismatch):
// if (!protoId.startsWith("spiffe://" + expectedTrustDomain + "/")) abort;

Try / catch

try {
    doc = client.getWorkloadCertificate();
} catch (SpiffeConnectionException e) {
    if (e.getMessage().contains("does not match the leaf certificate URI SAN")) {
        throw new SecurityException("Possible Workload API tampering or misconfigured SPIRE entry: " + e.getMessage(), e);
    } else throw e;
}

Prevention

When it happens

Trigger: getWorkloadCertificate when protoSpiffeId from X509SVID.getSpiffeId() differs from the SAN extracted by SpiffeValidator.validateLeaf(leaf).

Common situations: MitM/tampering on the Workload API socket; a mock or custom Workload API returning inconsistent data; agent bug after a version upgrade; trust domain reconfiguration where the server re-issued certs under a new domain while the entry still lists the old one.

Understand the failure class

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/bdd52bca10b926b3. Report an issue: GitHub.