diff --git a/src/d_main.c b/src/d_main.c
index fa9e21337ced42286e27b75a7bd2987ee62538e5..6e76672e04401181b7c7dca42afe2542ceb051d6 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1689,3 +1689,74 @@ const char *D_Home(void)
 	if (usehome) return userhome;
 	else return NULL;
 }
+
+static boolean check_top_dir(const char **path, const char *top)
+{
+	// empty string does NOT match
+	if (!strcmp(top, ""))
+		return false;
+
+	if (!startswith(*path, top))
+		return false;
+
+	*path += strlen(top);
+
+	// if it doesn't already end with a path separator,
+	// check if a separator follows
+	if (!endswith(top, PATHSEP))
+	{
+		if (startswith(*path, PATHSEP))
+			*path += strlen(PATHSEP);
+		else
+			return false;
+	}
+
+	return true;
+}
+
+static int cmp_strlen_desc(const void *a, const void *b)
+{
+	return ((int)strlen(*(const char*const*)b) - (int)strlen(*(const char*const*)a));
+}
+
+boolean D_IsPathAllowed(const char *path)
+{
+	const char *paths[] = {
+		srb2home,
+		srb2path,
+		cv_addons_folder.string
+	};
+
+	const size_t n_paths = sizeof paths / sizeof *paths;
+
+	size_t i;
+
+	// Sort folder paths by longest to shortest so
+	// overlapping paths work. E.g.:
+	// Path 1: /home/james/.srb2/addons
+	// Path 2: /home/james/.srb2
+	qsort(paths, n_paths, sizeof *paths, cmp_strlen_desc);
+
+	// These paths are allowed to be absolute
+	// path is offset so ".." can be checked only in the
+	// rest of the path
+	for (i = 0; i < n_paths; ++i)
+	{
+		if (check_top_dir(&path, paths[i]))
+			break;
+	}
+
+	// Only if none of the presets matched
+	if (i == n_paths)
+	{
+		// Cannot be an absolute path
+		if (M_IsPathAbsolute(path))
+			return false;
+	}
+
+	// Cannot traverse upwards
+	if (strstr(path, ".."))
+		return false;
+
+	return true;
+}
diff --git a/src/d_main.h b/src/d_main.h
index 8189a9f2b39f277ba6d5c854551a8e9d21bd35c1..7760351f365553c3df4422666762ea20279fb43d 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -44,6 +44,8 @@ void D_ProcessEvents(void);
 
 const char *D_Home(void);
 
+boolean D_IsPathAllowed(const char *path);
+
 //
 // BASE LEVEL
 //
diff --git a/src/p_setup.c b/src/p_setup.c
index 03a702b3061244ae1d1ebe50b8ce81e9c89bc1dd..132dc4259f262478487b1e4ab37d987a2552afaa 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -7860,8 +7860,10 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
 // Add a wadfile to the active wad files,
 // replace sounds, musics, patches, textures, sprites and maps
 //
-static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
+static boolean P_LoadAddon(UINT16 numlumps)
 {
+	const UINT16 wadnum = (UINT16)(numwadfiles-1);
+
 	size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
 	char *name;
 	lumpinfo_t *lumpinfo;
@@ -7883,6 +7885,12 @@ static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
 //	UINT16 flaPos, flaNum = 0;
 //	UINT16 mapPos, mapNum = 0;
 
+	if (numlumps == INT16_MAX)
+	{
+		refreshdirmenu |= REFRESHDIR_NOTLOADED;
+		return false;
+	}
+
 	switch(wadfiles[wadnum]->type)
 	{
 	case RET_PK3:
@@ -8051,34 +8059,25 @@ static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
 	return true;
 }
 
-boolean P_AddWadFile(const char *wadfilename)
+static boolean P_CheckAddonPath(const char *path)
 {
-	UINT16 numlumps, wadnum;
-
-	// Init file.
-	if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
+	if (!D_IsPathAllowed(path))
 	{
-		refreshdirmenu |= REFRESHDIR_NOTLOADED;
+		CONS_Alert(CONS_WARNING, "%s: tried to add file, location is not allowed\n", path);
 		return false;
 	}
-	else
-		wadnum = (UINT16)(numwadfiles-1);
 
-	return P_LoadAddon(wadnum, numlumps);
+	return true;
+}
+
+boolean P_AddWadFile(const char *wadfilename)
+{
+	return P_CheckAddonPath(wadfilename) &&
+		P_LoadAddon(W_InitFile(wadfilename, false, false));
 }
 
 boolean P_AddFolder(const char *folderpath)
 {
-	UINT16 numlumps, wadnum;
-
-	// Init file.
-	if ((numlumps = W_InitFolder(folderpath, false, false)) == INT16_MAX)
-	{
-		refreshdirmenu |= REFRESHDIR_NOTLOADED;
-		return false;
-	}
-	else
-		wadnum = (UINT16)(numwadfiles-1);
-
-	return P_LoadAddon(wadnum, numlumps);
+	return P_CheckAddonPath(folderpath) &&
+		P_LoadAddon(W_InitFolder(folderpath, false, false));
 }