java.net.URL.equals() — A Hidden Vulnerability in Whitelist Checks

Jul 6, 2025

TL;DR

java.net.URL.equals() performs a DNS lookup and considers two URLs equal if their IP addresses match — even when the domains are completely different. This can bypass whitelist checks and lead to SSRF or DNS rebinding attacks.

The Problem

Oracle explicitly documents this behavior:

Two hosts are considered equivalent if both host names can be resolved into the same IP addresses.

// Dangerous! DNS resolution + IP comparison
URL trusted = new URL("http://intranet.corp/");
URL userInput = new URL("http://evil.com/");

// If evil.com resolves to the same IP as intranet.corp
if (trusted.equals(userInput)) {  // returns true!
    openConnection(userInput);    // request goes to evil.com
}

Safe Alternatives

// If both domains resolve to the same IP:
url.equals(other)                     // true  — DNS resolution, unsafe
url.toExternalForm().equals(other)    // false — string comparison, safe
URI.create(url).equals(otherURI)      // false — no DNS, safe
url.getHost().equals(other.getHost()) // false — hostname only, safe

What to Look for in Code

// Dangerous patterns with java.net.URL
URL.equals(other)
HashSet<URL>.contains(url)
HashMap<URL, ?>.get(url)

// Safe alternatives
url.toString().equals(other.toString())
HashSet<String>.contains(url.toString())
Map<String, ?> with url.getHost() as key