CVE-2022-1713: Server-Side Request Forgery (SSRF) (CWE-918)
value: SSRF on /proxy in GitHub repository jgraph/drawio prior to 18.0.4. An attacker can make a request as the server and read its contents. This can lead to a leak of sensitive information.
CWE description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
CVSS v3 base score: 7.5
Published: 2022-05-16T15:15Z
Repository: https://github.com/jgraph/drawio
Language: Java
Files changed: src/main/java/com/mxgraph/online/ProxyServlet.java
Commit date: 2022-05-13 17:39:58 +0100
Commit message: 18.0.3 release

Diff: diff --git a/src/main/java/com/mxgraph/online/ProxyServlet.java b/src/main/java/com/mxgraph/online/ProxyServlet.java
index d7ea3c629..99a88937f 100644
--- a/src/main/java/com/mxgraph/online/ProxyServlet.java
+++ b/src/main/java/com/mxgraph/online/ProxyServlet.java
@@ -13,10 +13,11 @@ import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.UnknownHostException;
+import java.net.InetAddress;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -243,46 +244,55 @@ public class ProxyServlet extends HttpServlet
 		{
 			try
 			{
 				URL parsedUrl = new URL(url);
 				String protocol = parsedUrl.getProtocol();
-				String host = parsedUrl.getHost().toLowerCase();
+				String host = parsedUrl.getHost();
+				InetAddress address = InetAddress.getByName(host);
+				String hostAddress = address.getHostAddress();
+				host = host.toLowerCase();
 
 				return (protocol.equals("http") || protocol.equals("https"))
-						&& !host.endsWith(".internal")
-						&& !host.endsWith(".local")
-						&& !host.contains("localhost")
-						&& !host.startsWith("0.") // 0.0.0.0/8
-						&& !host.startsWith("10.") // 10.0.0.0/8
-						&& !host.startsWith("127.") // 127.0.0.0/8
-						&& !host.startsWith("169.254.") // 169.254.0.0/16
-						&& !host.startsWith("172.16.") // 172.16.0.0/12
-						&& !host.startsWith("172.17.") // 172.16.0.0/12
-						&& !host.startsWith("172.18.") // 172.16.0.0/12
-						&& !host.startsWith("172.19.") // 172.16.0.0/12
-						&& !host.startsWith("172.20.") // 172.16.0.0/12
-						&& !host.startsWith("172.21.") // 172.16.0.0/12
-						&& !host.startsWith("172.22.") // 172.16.0.0/12
-						&& !host.startsWith("172.23.") // 172.16.0.0/12
-						&& !host.startsWith("172.24.") // 172.16.0.0/12
-						&& !host.startsWith("172.25.") // 172.16.0.0/12
-						&& !host.startsWith("172.26.") // 172.16.0.0/12
-						&& !host.startsWith("172.27.") // 172.16.0.0/12
-						&& !host.startsWith("172.28.") // 172.16.0.0/12
-						&& !host.startsWith("172.29.") // 172.16.0.0/12
-						&& !host.startsWith("172.30.") // 172.16.0.0/12
-						&& !host.startsWith("172.31.") // 172.16.0.0/12
-						&& !host.startsWith("192.0.0.") // 192.0.0.0/24
-						&& !host.startsWith("192.168.") // 192.168.0.0/16
-						&& !host.startsWith("198.18.") // 198.18.0.0/15
-						&& !host.startsWith("198.19.") // 198.18.0.0/15
+						&& !address.isAnyLocalAddress()
+						&& !address.isLoopbackAddress()
+						&& !host.endsWith(".internal") // Redundant
+						&& !host.endsWith(".local") // Redundant
+						&& !host.contains("localhost") // Redundant
+						&& !hostAddress.startsWith("0.") // 0.0.0.0/8 
+						&& !hostAddress.startsWith("10.") // 10.0.0.0/8
+						&& !hostAddress.startsWith("127.") // 127.0.0.0/8
+						&& !hostAddress.startsWith("169.254.") // 169.254.0.0/16
+						&& !hostAddress.startsWith("172.16.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.17.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.18.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.19.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.20.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.21.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.22.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.23.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.24.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.25.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.26.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.27.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.28.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.29.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.30.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("172.31.") // 172.16.0.0/12
+						&& !hostAddress.startsWith("192.0.0.") // 192.0.0.0/24
+						&& !hostAddress.startsWith("192.168.") // 192.168.0.0/16
+						&& !hostAddress.startsWith("198.18.") // 198.18.0.0/15
+						&& !hostAddress.startsWith("198.19.") // 198.18.0.0/15
 						&& !host.endsWith(".arpa"); // reverse domain (needed?)
 			}
 			catch (MalformedURLException e)
 			{
 				return false;
 			}
+			catch (UnknownHostException e)
+			{
+				return false;
+			}
 		}
 		else
 		{
 			return false;
 		}

Vulnerable code: 				String host = parsedUrl.getHost().toLowerCase();
						&& !host.endsWith(".internal")
						&& !host.endsWith(".local")
						&& !host.contains("localhost")
						&& !host.startsWith("0.") // 0.0.0.0/8
						&& !host.startsWith("10.") // 10.0.0.0/8
						&& !host.startsWith("127.") // 127.0.0.0/8
						&& !host.startsWith("169.254.") // 169.254.0.0/16
						&& !host.startsWith("172.16.") // 172.16.0.0/12
						&& !host.startsWith("172.17.") // 172.16.0.0/12
						&& !host.startsWith("172.18.") // 172.16.0.0/12
						&& !host.startsWith("172.19.") // 172.16.0.0/12
						&& !host.startsWith("172.20.") // 172.16.0.0/12
						&& !host.startsWith("172.21.") // 172.16.0.0/12
						&& !host.startsWith("172.22.") // 172.16.0.0/12
						&& !host.startsWith("172.23.") // 172.16.0.0/12
						&& !host.startsWith("172.24.") // 172.16.0.0/12
						&& !host.startsWith("172.25.") // 172.16.0.0/12
						&& !host.startsWith("172.26.") // 172.16.0.0/12
						&& !host.startsWith("172.27.") // 172.16.0.0/12
						&& !host.startsWith("172.28.") // 172.16.0.0/12
						&& !host.startsWith("172.29.") // 172.16.0.0/12
						&& !host.startsWith("172.30.") // 172.16.0.0/12
						&& !host.startsWith("172.31.") // 172.16.0.0/12
						&& !host.startsWith("192.0.0.") // 192.0.0.0/24
						&& !host.startsWith("192.168.") // 192.168.0.0/16
						&& !host.startsWith("198.18.") // 198.18.0.0/15
						&& !host.startsWith("198.19.") // 198.18.0.0/15
Fixed code: import java.net.InetAddress;
				String host = parsedUrl.getHost();
				InetAddress address = InetAddress.getByName(host);
				String hostAddress = address.getHostAddress();
				host = host.toLowerCase();
						&& !address.isAnyLocalAddress()
						&& !address.isLoopbackAddress()
						&& !host.endsWith(".internal") // Redundant
						&& !host.endsWith(".local") // Redundant
						&& !host.contains("localhost") // Redundant
						&& !hostAddress.startsWith("0.") // 0.0.0.0/8 
						&& !hostAddress.startsWith("10.") // 10.0.0.0/8
						&& !hostAddress.startsWith("127.") // 127.0.0.0/8
						&& !hostAddress.startsWith("169.254.") // 169.254.0.0/16
						&& !hostAddress.startsWith("172.16.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.17.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.18.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.19.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.20.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.21.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.22.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.23.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.24.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.25.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.26.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.27.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.28.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.29.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.30.") // 172.16.0.0/12
						&& !hostAddress.startsWith("172.31.") // 172.16.0.0/12
						&& !hostAddress.startsWith("192.0.0.") // 192.0.0.0/24
						&& !hostAddress.startsWith("192.168.") // 192.168.0.0/16
						&& !hostAddress.startsWith("198.18.") // 198.18.0.0/15
						&& !hostAddress.startsWith("198.19.") // 198.18.0.0/15
			catch (UnknownHostException e)
			{
				return false;
			}