{"record":{"id":"bb8c97311db31db2","repo":"quarkusio/quarkus","slug":"signing-certificate-spiffe-id-must-not-have-a-path","errorCode":null,"errorMessage":"Signing certificate SPIFFE ID must not have a path component: ${uriSan}","messagePattern":"Signing certificate SPIFFE ID must not have a path component: (.+?)","errorType":"exception","errorClass":"SpiffeConnectionException","httpStatus":null,"severity":"error","filePath":"extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java","lineNumber":60,"sourceCode":"    // X.509-SVID 3.2 SHOULD: signing cert SHOULD itself be an SVID (not enforced — upstream CA may not be SPIFFE-aware)\n    // X.509-SVID 3.2 SHOULD: signing cert SHOULD reside in the trust domain of leaf SVIDs it issues (not enforced — cross-domain signing is allowed)\n    static void validateIntermediate(X509Certificate cert) throws SpiffeConnectionException {\n        if (cert.getBasicConstraints() < 0) {\n            throw new SpiffeConnectionException(\n                    \"Signing certificate must have CA flag set to true: \" + cert.getSubjectX500Principal());\n        }\n        boolean[] keyUsage = cert.getKeyUsage();\n        if (keyUsage == null || keyUsage.length <= 5 || !keyUsage[5]) {\n            throw new SpiffeConnectionException(\n                    \"Signing certificate must have 'keyCertSign' as key usage: \" + cert.getSubjectX500Principal());\n        }\n        // X.509-SVID 3.2 MUST: if signing cert has a SPIFFE ID, it must not have a path component\n        String uriSan = extractOptionalUriSan(cert);\n        if (uriSan != null && uriSan.startsWith(SPIFFE_URI_PREFIX)) {\n            URI uri = URI.create(uriSan);\n            String path = uri.getPath();\n            if (path != null && !path.isEmpty() && !\"/\".equals(path)) {\n                throw new SpiffeConnectionException(\n                        \"Signing certificate SPIFFE ID must not have a path component: \" + uriSan);\n            }\n        }\n    }\n\n    static void validateSpiffeId(String spiffeId) throws SpiffeConnectionException {\n        if (spiffeId == null || spiffeId.isEmpty()) {\n            throw new SpiffeConnectionException(\"SPIFFE ID must not be empty\");\n        }\n        if (spiffeId.length() > MAX_SPIFFE_ID_LENGTH) {\n            throw new SpiffeConnectionException(\"SPIFFE ID exceeds maximum length of \" + MAX_SPIFFE_ID_LENGTH\n                    + \" bytes: \" + spiffeId.length());\n        }\n\n        if (!spiffeId.startsWith(SPIFFE_URI_PREFIX)) {\n            throw new SpiffeConnectionException(\"SPIFFE ID must have 'spiffe://' scheme: \" + spiffeId);\n        }\n        if (spiffeId.contains(\"%\")) {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java#L42-L78","documentation":"Per the X.509-SVID profile, if a signing certificate carries a SPIFFE ID in its URI SAN, that ID must be a trust-domain root with no path component (e.g. spiffe://example.org). SpiffeValidator.validateIntermediate rejects signing certs whose SPIFFE URI has a non-empty path, since only leaf workload identities may have paths.","triggerScenarios":"An intermediate/signing certificate contains a URI SAN like spiffe://example.org/sa/intermediate — a path component — and the chain is validated via SpiffeValidator.validateIntermediate.","commonSituations":"CA certs accidentally issued with workload-style identity SANs copied from a leaf template; custom PKI automation stamping the same SPIFFE ID pattern onto CAs and leaves.","solutions":["Reissue the signing certificate with either no SPIFFE URI SAN or a path-less SPIFFE ID (spiffe://<trust-domain>).","If the CA needs no workload identity, drop the URI SAN entirely.","Fix PKI automation so SPIFFE ID paths are only applied to leaf SVIDs."],"exampleFix":"// before\nURI SAN: spiffe://example.org/sa/intermediate\n// after\nURI SAN: spiffe://example.org","handlingStrategy":"validation","validationCode":"String san = extractUriSan(cert);\nif (san != null && san.startsWith(\"spiffe://\")\n        && new URI(san).getPath() != null && !new URI(san).getPath().isEmpty()) {\n    throw new IllegalArgumentException(\"CA SPIFFE ID must not have a path: \" + san);\n}","typeGuard":null,"tryCatchPattern":"try {\n    connection.establish();\n} catch (SpiffeConnectionException e) {\n    if (e.getMessage().contains(\"path component\")) {\n        log.error(\"Signing cert carries a workload-style SPIFFE ID; reissue CA cert\", e);\n    }\n    throw e;\n}","preventionTips":["Only put path-less SPIFFE IDs (or none) on CA certificates","Keep identity-path stamping automation separate from CA issuance","Review CA cert URI SANs after PKI template changes"],"tags":["spiffe","x509","san","certificate-chain"],"backgroundTag":"spiffe-id-validation-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}