diff --git a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/CreateLinksController.java b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/CreateLinksController.java
index 8d0ea523443a3bfb9345279eb18581b4226c6fd1..b3dfe7fc7e1e36bfe45dbbde519cc426c8933c6b 100644
--- a/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/CreateLinksController.java
+++ b/vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/CreateLinksController.java
@@ -10,6 +10,8 @@ import it.inaf.ia2.vospace.ui.data.CreateLinkRequest;
 import it.inaf.ia2.vospace.ui.exception.BadRequestException;
 import it.inaf.ia2.vospace.ui.exception.VOSpaceStatusException;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
@@ -18,6 +20,7 @@ import net.ivoa.xml.vospace.v2.LinkNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -31,6 +34,9 @@ public class CreateLinksController extends BaseController {
 
     private static final Logger LOG = LoggerFactory.getLogger(CreateLinksController.class);
 
+    @Value("${list-of-links.limit:1000}")
+    private int listOfLinksSizeLimit;
+
     @Autowired
     private VOSpaceClient client;
 
@@ -63,11 +69,17 @@ public class CreateLinksController extends BaseController {
         List<CompletableFuture<?>> currentHttpCallsGroup = new ArrayList<>();
         httpCallsGroups.add(currentHttpCallsGroup);
 
-        for (String url : fileContent.replaceAll("\\r\\n?", "\n").split("\n")) { // normalize newlines and split on them
+        // normalize newlines and split on them
+        String[] urls = fileContent.replaceAll("\\r\\n?", "\n").split("\n");
+        if (urls.length > listOfLinksSizeLimit) {
+            throw new BadRequestException("List is too large: " + urls.length + " lines detected, limit is " + listOfLinksSizeLimit);
+        }
+
+        for (String url : urls) {
             if (!url.isBlank()) {
 
-                String fileName = url.substring(url.lastIndexOf("/") + 1);
-                String uri = parent.getUri() + "/" + fileName;
+                url = url.trim();
+                String uri = parent.getUri() + "/" + getFileNameFromUrl(url);
 
                 LinkNode link = new LinkNode();
                 link.setUri(uri);
@@ -89,6 +101,28 @@ public class CreateLinksController extends BaseController {
         return ResponseEntity.noContent().build();
     }
 
+    private String getFileNameFromUrl(String url) {
+
+        try {
+            // parse URL and remove the query string
+            String urlPath = new URL(url).getPath();
+            if (urlPath.endsWith("/")) {
+                // remove last char if it is a slash
+                urlPath = urlPath.substring(0, urlPath.length() - 1);
+            }
+            if (urlPath.isEmpty() || !urlPath.contains("/")) {
+                throw new BadRequestException("Unable to extract file name from URL " + url);
+            }
+            String fileName = urlPath.substring(urlPath.lastIndexOf("/") + 1);
+            if (fileName.isEmpty()) {
+                throw new BadRequestException("Unable to extract file name from URL " + url);
+            }
+            return fileName;
+        } catch (MalformedURLException ex) {
+            throw new BadRequestException("Invalid URL: " + url);
+        }
+    }
+
     private ContainerNode getFolder(String folderPath) {
         try {
             return (ContainerNode) client.getNode("/" + folderPath);
diff --git a/vospace-ui-backend/src/main/resources/application.properties b/vospace-ui-backend/src/main/resources/application.properties
index e72cdd41809901cb05e5de710f61edef1e2ca0bb..dc3177cd4ef06e3a88f9a9176f93501754269baf 100644
--- a/vospace-ui-backend/src/main/resources/application.properties
+++ b/vospace-ui-backend/src/main/resources/application.properties
@@ -11,6 +11,7 @@ cors.allowed.origin=http://localhost:8080
 logging.level.it.inaf=TRACE
 
 trusted.eppn.scope=inaf.it
+list-of-links.limit=1000
 
 support.contact.label=IA2 team
 support.contact.email=ia2@inaf.it
diff --git a/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/CreateLinksControllerTest.java b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/CreateLinksControllerTest.java
index f1eb4d7a69e1ad5b676b528214fa6995aba7995c..92c56f37b89ce9095db770d5d8a58e844be22f56 100644
--- a/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/CreateLinksControllerTest.java
+++ b/vospace-ui-backend/src/test/java/it/inaf/ia2/vospace/ui/controller/CreateLinksControllerTest.java
@@ -10,6 +10,7 @@ import it.inaf.ia2.aa.data.User;
 import it.inaf.ia2.vospace.ui.client.VOSpaceClient;
 import it.inaf.ia2.vospace.ui.data.CreateLinkRequest;
 import it.inaf.ia2.vospace.ui.exception.VOSpaceStatusException;
+import java.util.Collections;
 import net.ivoa.xml.vospace.v2.ContainerNode;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -109,6 +110,41 @@ public class CreateLinksControllerTest {
         verify(client, times(75)).createNode(any());
     }
 
+    @Test
+    public void testInvalidUrl() throws Exception {
+        testInvalidContent("foo");
+    }
+
+    @Test
+    public void testInvalidUrlNoFile() throws Exception {
+        testInvalidContent("http://archives.ia2.inaf.it/");
+    }
+
+    @Test
+    public void testInvalidUrlNoFileNoSlash() throws Exception {
+        testInvalidContent("http://archives.ia2.inaf.it");
+    }
+
+    @Test
+    public void testTooManyLinks() throws Exception {
+        testInvalidContent(String.join("\n", Collections.nCopies(1500, "http://archives.ia2.inaf.it/files/aao/SC182172.fits.gz")));
+    }
+
+    private void testInvalidContent(String fileContent) throws Exception {
+
+        ContainerNode myFolder = new ContainerNode();
+        when(client.getNode("/path/to/myfolder")).thenReturn(myFolder);
+
+        MockMultipartFile file = new MockMultipartFile("file", fileContent.getBytes());
+
+        mockMvc.perform(multipart("/uploadLinks")
+                .file(file)
+                .param("folder", "path/to/myfolder")
+                .sessionAttr("user_data", user))
+                .andDo(print())
+                .andExpect(status().isBadRequest());
+    }
+
     private MockMultipartFile getListOfLinksMockMultipartFile() throws Exception {
         return new MockMultipartFile("file", UploadControllerTest.class.getClassLoader().getResourceAsStream("list-of-links.txt"));
     }
diff --git a/vospace-ui-backend/src/test/resources/list-of-links.txt b/vospace-ui-backend/src/test/resources/list-of-links.txt
index 0474fcedd9722a356c2a0d229ba8c4e625aff7e3..b3d48ffa0597fb96ef2bddf86512e02a065784e3 100644
--- a/vospace-ui-backend/src/test/resources/list-of-links.txt
+++ b/vospace-ui-backend/src/test/resources/list-of-links.txt
@@ -1,7 +1,7 @@
 http://archives.ia2.inaf.it/files/aao/SC182159.fits.gz
-http://archives.ia2.inaf.it/files/aao/SC182160.fits.gz
-http://archives.ia2.inaf.it/files/aao/SC182161.fits.gz
-http://archives.ia2.inaf.it/files/aao/SC182169.fits.gz
+http://archives.ia2.inaf.it/files/aao/SC182160.fits.gz/
+http://archives.ia2.inaf.it/files/aao/SC182161.fits.gz?query=xxx
+http://archives.ia2.inaf.it/files/aao/SC182169.fits.gz  
 http://archives.ia2.inaf.it/files/aao/SC182170.fits.gz
 http://archives.ia2.inaf.it/files/aao/SC182171.fits.gz
 http://archives.ia2.inaf.it/files/aao/SC182172.fits.gz
diff --git a/vospace-ui-frontend/src/components/modal/CreateLinksModal.vue b/vospace-ui-frontend/src/components/modal/CreateLinksModal.vue
index ec1f5409cffe17e33cb3a6fd0231b9291371ac0a..eee6cbc45f1afe1d1b56257bfd92d05e9730dbf7 100644
--- a/vospace-ui-frontend/src/components/modal/CreateLinksModal.vue
+++ b/vospace-ui-frontend/src/components/modal/CreateLinksModal.vue
@@ -24,7 +24,10 @@
     <b-form-invalid-feedback id="node-name-input-feedback" class="text-right">{{nodeNameError}}</b-form-invalid-feedback>
   </b-form>
   <b-form inline v-if="mode === 'multiple'">
-    <p>Upload list of links (separated by newlines)</p>
+    <p>
+      Upload list of links (separated by newlines)<br />
+      <em>Maximum 1000 links per file!</em>
+    </p>
     <b-form-file class="text-left" v-model="file" :multiple="false" placeholder="Choose your file or drop it here..." drop-placeholder="Drop file here..." :state="fileState"></b-form-file>
     <b-form-invalid-feedback id="file-input-feedback" class="text-right">{{fileError}}</b-form-invalid-feedback>
   </b-form>