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
- Ensure the Workload API socket is the genuine agent unix socket (check for rogue listeners on the path).
- Recreate the SPIRE registration entry so the spiffeID matches the identity actually issued.
- Restart the agent and re-request the certificate; check agent/server versions.
- 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
- Mount the agent socket read-only at the documented path and check for rogue listeners
- Keep SPIRE entry spiffeIDs aligned with issued identities
- Pin and verify trust domain configuration
- Do not proxy or intercept the Workload API socket
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- JWT-SVID from SPIRE agent has no token
- JWT-SVID from SPIRE agent is already expired
- X.509-SVID response from SPIRE agent contains no SVIDs
- X.509-SVID response from SPIRE agent has empty certificate c
- X.509-SVID response from SPIRE agent has empty private key
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/bdd52bca10b926b3.
Report an issue: GitHub.