Index: wget.git-salsa-debian/src/ftp-basic.c
===================================================================
--- wget.git-salsa-debian.orig/src/ftp-basic.c
+++ wget.git-salsa-debian/src/ftp-basic.c
@@ -623,10 +623,19 @@ ftp_pasv (int csock, ip_address *addr, i
   int nwritten, i;
   uerr_t err;
   unsigned char tmp[6];
+  ip_address peer_addr;
 
   assert (addr != NULL);
   assert (port != NULL);
 
+  /* Remember who we are talking to on the control connection, so that
+     the address returned in the PASV response can be checked below.
+     Accepting an arbitrary server-supplied address would let a
+     malicious FTP server redirect our data connection to any host of
+     its choosing (SSRF).  */
+  if (!socket_ip_address (csock, &peer_addr, ENDPOINT_PEER))
+    return FTPINVPASV;
+
   xzero (*addr);
 
   /* Form the request.  */
@@ -677,6 +686,16 @@ ftp_pasv (int csock, ip_address *addr, i
   memcpy (IP_INADDR_DATA (addr), tmp, 4);
   *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
 
+  /* Reject the response if the advertised address does not match the
+     control connection's peer.  */
+  if (peer_addr.family != AF_INET
+      || memcmp (IP_INADDR_DATA (addr), IP_INADDR_DATA (&peer_addr), 4) != 0)
+    {
+      xzero (*addr);
+      *port = 0;
+      return FTPINVPASV;
+    }
+
   return FTPOK;
 }
 
@@ -692,10 +711,19 @@ ftp_lpsv (int csock, ip_address *addr, i
   uerr_t err;
   unsigned char tmp[16];
   unsigned char tmpprt[2];
+  ip_address peer_addr;
 
   assert (addr != NULL);
   assert (port != NULL);
 
+  /* Remember who we are talking to on the control connection, so that
+     the address returned in the LPSV response can be checked below.
+     Accepting an arbitrary server-supplied address would let a
+     malicious FTP server redirect our data connection to any host of
+     its choosing (SSRF).  */
+  if (!socket_ip_address (csock, &peer_addr, ENDPOINT_PEER))
+    return FTPINVPASV;
+
   xzero (*addr);
 
   /* Form the request.  */
@@ -842,6 +870,18 @@ ftp_lpsv (int csock, ip_address *addr, i
       DEBUGP (("*port is: %d\n", *port));
     }
 
+  /* Reject the response if the advertised address does not match the
+     control connection's peer.  */
+  if (peer_addr.family != addr->family
+      || memcmp (IP_INADDR_DATA (addr), IP_INADDR_DATA (&peer_addr),
+                 af == 4 ? 4 : 16) != 0)
+    {
+      xzero (*addr);
+      *port = 0;
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
   xfree (respline);
   return FTPOK;
 }
Index: wget.git-salsa-debian/src/ftp-ls.c
===================================================================
--- wget.git-salsa-debian.orig/src/ftp-ls.c
+++ wget.git-salsa-debian/src/ftp-ls.c
@@ -82,6 +82,35 @@ clean_line (char *line, int len)
   return len;
 }
 
+/* Return true if TARGET is not safe to use as the target of a
+   symbolic link created locally to mirror a symlink reported by an
+   FTP server: an absolute path, or a relative path containing a ".."
+   path component, can point outside of the download directory.  A
+   malicious or compromised FTP server could otherwise use a crafted
+   directory listing to make Wget create a symlink pointing anywhere
+   on the local file system.  */
+static bool
+ftp_ls_unsafe_symlink_target (const char *target)
+{
+  const char *p;
+
+  if (!*target)
+    return true;
+
+  if (*target == '/')
+    return true;
+
+  for (p = target; *p; p++)
+    {
+      if (p[0] == '.' && p[1] == '.'
+          && (p[2] == '\0' || p[2] == '/')
+          && (p == target || p[-1] == '/'))
+        return true;
+    }
+
+  return false;
+}
+
 /* Convert the Un*x-ish style directory listing stored in FILE to a
    linked list of fileinfo (system-independent) entries.  The contents
    of FILE are considered to be produced by the standard Unix `ls -la'
@@ -294,6 +323,18 @@ ftp_parse_unix_ls (FILE *fp, int ignore_
                           error = 1;
                           break;
                         }
+                      /* Reject symlink targets that could escape the
+                         download directory (absolute paths, or paths
+                         containing a ".." component) before storing
+                         them; they are later passed directly to
+                         symlink().  */
+                      if (ftp_ls_unsafe_symlink_target (p + 4))
+                        {
+                          DEBUGP (("Rejecting unsafe symlink target: %s\n",
+                                   p + 4));
+                          error = 1;
+                          break;
+                        }
                       cur.linkto = xstrdup (p + 4);
                       DEBUGP (("link to: %s\n", cur.linkto));
                       /* And separate it from the file name.  */
