{"record":{"id":"799f62fd4960f60a","repo":"grpc/grpc-java","slug":"multiple-uri-san-values-found-in-the-leaf-cert","errorCode":null,"errorMessage":"Multiple URI SAN values found in the leaf cert.","messagePattern":"Multiple URI SAN values found in the leaf cert\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/SpiffeUtil.java","lineNumber":146,"sourceCode":"   *\n   * @param certChain certificate chain to extract SPIFFE ID from\n   */\n  public static Optional<SpiffeId> extractSpiffeId(X509Certificate[] certChain)\n      throws CertificateParsingException {\n    checkArgument(checkNotNull(certChain, \"certChain\").length > 0, \"certChain can't be empty\");\n    Collection<List<?>> subjectAltNames = certChain[0].getSubjectAlternativeNames();\n    if (subjectAltNames == null) {\n      return Optional.absent();\n    }\n    String uri = null;\n    // Search for the unique URI SAN.\n    for (List<?> altName : subjectAltNames) {\n      if (altName.size() < 2 ) {\n        continue;\n      }\n      if (URI_SAN_TYPE.equals(altName.get(0))) {\n        if (uri != null) {\n          throw new IllegalArgumentException(\"Multiple URI SAN values found in the leaf cert.\");\n        }\n        uri = (String) altName.get(1);\n      }\n    }\n    if (uri == null) {\n      return Optional.absent();\n    }\n    return Optional.of(parse(uri));\n  }\n\n  /**\n   * Loads a SPIFFE trust bundle from a file, parsing it from the JSON format.\n   * In case of success, returns {@link SpiffeBundle}.\n   * If any element of the JSON content is invalid or unsupported, an\n   * {@link IllegalArgumentException} is thrown and the entire Bundle is considered invalid.\n   *\n   * @param trustBundleFile the file path to the JSON file containing the trust bundle\n   * @see <a href=\"https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md\">JSON format</a>","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/SpiffeUtil.java#L128-L164","documentation":"SpiffeUtil.extractSpiffeId derives a SPIFFE ID from the leaf certificate's Subject Alternative Names. The SPIFFE spec requires exactly one URI SAN, so if the leaf certificate contains more than one URI SAN entry this IllegalArgumentException is thrown.","triggerScenarios":"Presenting an mTLS leaf certificate whose SAN extension contains two or more URI-type entries (URI_SAN_TYPE) to extractSpiffeId during SPIFFE-based workload identity extraction.","commonSituations":"Certificates issued by CAs that add both a SPIFFE URI and another URI SAN; certificate templates with multiple DNS/URI entries; migrating certificates that retained legacy URIs.","solutions":["Reissue the leaf certificate with exactly one URI SAN containing the SPIFFE ID (spiffe://trust-domain/workload)","Remove extra URI SAN entries from the certificate template at your CA","Verify with: openssl x509 -in cert.pem -text | grep -A2 'URI' — expect exactly one URI entry"],"exampleFix":"// before (openssl req san config)\nsubjectAltName = URI:spiffe://ns/default/sa/a, URI:https://example.com\n// after\nsubjectAltName = URI:spiffe://ns/default/sa/a","handlingStrategy":"try-catch","validationCode":"// Inspect leaf cert SANs before use\nCollection<List<?>> sans = cert.getSubjectAlternativeNames();\nlong uriCount = sans == null ? 0 : sans.stream()\n    .filter(s -> s.size() >= 2 && s.get(0) instanceof Integer && (Integer) s.get(0) == 6)\n    .count();\nif (uriCount > 1) throw new IllegalStateException(\"Leaf cert has \" + uriCount + \" URI SANs\");","typeGuard":null,"tryCatchPattern":"try {\n  Optional<String> spiffeId = SpiffeUtil.extractSpiffeId(certs);\n} catch (IllegalArgumentException e) {\n  log.error(\"Leaf cert has multiple URI SANs — reissue with exactly one\", e);\n  failClosed();\n}","preventionTips":["Issue leaf certs with exactly one URI SAN holding the SPIFFE ID","Audit CA templates for extra URI SAN entries","Check certs with openssl before deploying: openssl x509 -text | grep 'URI:'"],"tags":["grpc","spiffe","mtls","certificate","san"],"backgroundTag":"invalid-certificate-san","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}