VYPR
Unrated severityOSV Advisory· Published Aug 24, 2018· Updated Aug 5, 2024

CVE-2018-15536

CVE-2018-15536

Description

/filemanager/ajax_calls.php in tecrail Responsive FileManager before 9.13.4 does not properly validate file paths in archives, allowing for the extraction of crafted archives to overwrite arbitrary files via an extract action, aka Directory Traversal.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Responsive FileManager before 9.13.4 fails to validate file paths in archives, allowing directory traversal during extraction to overwrite arbitrary files.

Vulnerability

The vulnerability resides in /filemanager/ajax_calls.php when handling the extract action. The code does not validate file paths contained within uploaded archives, allowing directory traversal sequences (e.g., ../../tmp/source.txt) to be processed. This affects tecrail Responsive FileManager versions before 9.13.4 [1].

Exploitation

An attacker must be an authenticated user with the ability to upload archives via the file manager interface. The attacker crafts a ZIP archive containing entries with path traversal payloads. A POST request is sent to /filemanager/ajax_calls.php?action=extract with the path parameter pointing to the uploaded archive. The server extracts the archive without sanitizing paths, writing files to arbitrary locations on the filesystem [1].

Impact

Successful exploitation allows an authenticated attacker to overwrite arbitrary files on the server. This could lead to code execution (e.g., overwriting PHP files in web-accessible directories) or denial of service. The provided example demonstrates writing to /tmp/source.txt, but the impact depends on the target file's location and permissions [1].

Mitigation

The vulnerability is fixed in version 9.13.4, released on or before August 24, 2018. Users should upgrade to this version or later. No workarounds are documented. The CVE is not listed on the CISA Known Exploited Vulnerabilities catalog [1].

AI Insight generated on May 26, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
a50cac88ebcf

version 9.13.4

10 files changed · +133 93
  • changelog.txt+14 0 modified
    @@ -1,5 +1,19 @@
     Responsive Filemanager Changelog 
     
    +*********************************************************
    +*  RFM 9.13.4
    +*********************************************************
    +- fix Directory Traversal Allows to Read Any File (thanks to Simon Uvarov for reporting)
    +- fix Path Traversal While Upacking Archives (thanks to Simon Uvarov for reporting)
    +- Fix foreach warning on URL upload
    +- Fix http https URL upload
    +- add toggle on config for extract_files
    +- prevent image creation for broken links in URL upload (thanks to davodavodavo3)
    +- Migrate to yarn on development (thanks to mklkj)
    +- code refactoring
    +
    +
    +
     *********************************************************
     *  RFM 9.13.3
     *********************************************************
    
  • filemanager/ajax_calls.php+34 43 modified
    @@ -23,6 +23,21 @@
     	response(trans('Lang_Not_Found').AddErrorLocation())->send();
     	exit;
     }
    +
    +
    +//check $_GET['file']
    +if(isset($_GET['file']) && !checkRelativePath($_GET['file'])) {
    +    response(trans('wrong path'))->send();
    +    exit;
    +}
    +
    +//check $_GET['file']
    +if(isset($_GET['path']) && !checkRelativePath($_GET['path'])) {
    +    response(trans('wrong path'))->send();
    +    exit;
    +}
    +
    +
     $ftp = ftp_con($config);
     
     if(isset($_GET['action']))
    @@ -83,12 +98,7 @@
     		case 'save_img':
     			$info = pathinfo($_POST['name']);
     
    -			if (
    -				strpos($_POST['path'], '/') === 0
    -				|| strpos($_POST['path'], '../') !== false
    -				|| strpos($_POST['path'], '..\\') !== false
    -				|| strpos($_POST['path'], './') === 0
    -				|| (strpos($_POST['url'], 'http://s3.amazonaws.com/feather') !== 0 && strpos($_POST['url'], 'https://s3.amazonaws.com/feather') !== 0)
    +			if ((strpos($_POST['url'], 'http://s3.amazonaws.com/feather') !== 0 && strpos($_POST['url'], 'https://s3.amazonaws.com/feather') !== 0)
     				|| $_POST['name'] != fix_filename($_POST['name'], $config)
     				|| ! in_array(strtolower($info['extension']), array( 'jpg', 'jpeg', 'png' ))
     			)
    @@ -135,15 +145,9 @@
     			}
     			break;
     		case 'extract':
    -			if (	strpos($_POST['path'], '/') === 0 
    -				|| strpos($_POST['path'], '../') !== false 
    -				|| strpos($_POST['path'], '..\\') !== false 
    -				|| strpos($_POST['path'], './') === 0)
    -			{
    -				response(trans('wrong path'.AddErrorLocation()))->send();
    -				exit;
    +			if(!$config['extract_files']){
    +				response(trans('wrong action'))->send();
     			}
    -
     			if($ftp){
     				$path = $config['ftp_base_url'].$config['upload_dir'] . $_POST['path'];
     				$base_folder = $config['ftp_base_url'].$config['upload_dir'] . fix_dirname($_POST['path']) . "/";
    @@ -186,28 +190,24 @@
     							exit;
     						}
     
    -						//make all the folders
    -						for ($i = 0; $i < $zip->numFiles; $i++)
    -						{
    -							$OnlyFileName = $zip->getNameIndex($i);
    -							$FullFileName = $zip->statIndex($i);
    -							if (substr($FullFileName['name'], -1, 1) == "/")
    -							{
    -								create_folder($base_folder . $FullFileName['name']);
    -							}
    -						}
    -						//unzip into the folders
    +						//make all the folders and unzip into the folders
     						for ($i = 0; $i < $zip->numFiles; $i++)
     						{
    -							$OnlyFileName = $zip->getNameIndex($i);
     							$FullFileName = $zip->statIndex($i);
     
    -							if ( ! (substr($FullFileName['name'], -1, 1) == "/"))
    -							{
    -								$fileinfo = pathinfo($OnlyFileName);
    -								if (in_array(strtolower($fileinfo['extension']), $config['ext']))
    +							if(checkRelativePath($FullFileName['name'])){
    +								if (substr($FullFileName['name'], -1, 1) == "/")
     								{
    -									copy('zip://' . $path . '#' . $OnlyFileName, $base_folder . $FullFileName['name']);
    +									create_folder($base_folder . $FullFileName['name']);
    +								}
    +
    +								if ( ! (substr($FullFileName['name'], -1, 1) == "/"))
    +								{
    +									$fileinfo = pathinfo($FullFileName['name']);
    +									if (in_array(strtolower($fileinfo['extension']), $config['ext']))
    +									{
    +										copy('zip://' . $path . '#' . $FullFileName['name'], $base_folder . $FullFileName['name']);
    +									}
     								}
     							}
     						}
    @@ -232,7 +232,7 @@
     					$phar = new PharData($path);
     					$phar->decompressFiles();
     					$files = array();
    -					check_files_extensions_on_phar($phar, $files, '', $config['ext']);
    +					check_files_extensions_on_phar($phar, $files, '', $config);
     					$phar->extractTo($base_folder, $files, true);
     
     					break;
    @@ -365,16 +365,7 @@
     		case 'copy_cut':
     			if ($_POST['sub_action'] != 'copy' && $_POST['sub_action'] != 'cut')
     			{
    -				response(trans('wrong sub-action').AddErrorLocation())->send();
    -				exit;
    -			}
    -
    -			if (strpos($_POST['path'],'../') !== FALSE
    -				|| strpos($_POST['path'],'./') !== FALSE 
    -				|| strpos($_POST['path'],'..\\') !== FALSE
    -				|| strpos($_POST['path'],'.\\') !== FALSE )
    -			{
    -				response(trans('wrong path'.AddErrorLocation()))->send();
    +				response(trans('wrong sub-action'))->send();
     				exit;
     			}
     
    @@ -611,7 +602,7 @@
     
     			if ($sub_action != 'preview' && $sub_action != 'edit')
     			{
    -				response(trans('wrong action').AddErrorLocation())->send();
    +				response(trans('wrong action'))->send();
     				exit;
     			}
     
    
  • filemanager/config/config.php+1 0 modified
    @@ -329,6 +329,7 @@
     	'rename_files'                            => true,
     	'rename_folders'                          => true,
     	'duplicate_files'                         => true,
    +	'extract_files'                           => true,
     	'copy_cut_files'                          => true, // for copy/cut files
     	'copy_cut_dirs'                           => true, // for copy/cut directories
     	'chmod_files'                             => true, // change file permissions
    
  • filemanager/dialog.php+8 13 modified
    @@ -47,15 +47,8 @@
     }elseif(isset($_SESSION['RF']['fldr']) && !empty($_SESSION['RF']['fldr'])){
     	$subdir_path = rawurldecode(trim(strip_tags($_SESSION['RF']['fldr']),"/"));
     }
    -$subdir_path_decoded = urldecode($subdir_path);
    -if (strpos($subdir_path,'../') === FALSE
    -	&& strpos($subdir_path,'./') === FALSE
    -	&& strpos($subdir_path,'..\\') === FALSE
    -	&& strpos($subdir_path,'.\\') === FALSE
    -	&& strpos($subdir_path_decoded,'../') === FALSE
    -	&& strpos($subdir_path_decoded,'./') === FALSE
    -	&& strpos($subdir_path_decoded,'..\\') === FALSE
    -	&& strpos($subdir_path_decoded,'.\\') === FALSE)
    +
    +if ( checkRelativePath($subdir_path))
     {
     	$subdir = strip_tags($subdir_path) ."/";
     	$_SESSION['RF']['fldr'] = $subdir_path;
    @@ -99,9 +92,10 @@
     }
     $rfm_subfolder = '';
     
    -if (!empty($_SESSION['RF']["subfolder"]) && strpos($_SESSION['RF']["subfolder"],'../') === FALSE && strpos($_SESSION['RF']["subfolder"],'..\\') === FALSE
    -&& strpos($_SESSION['RF']["subfolder"],'./') === FALSE && strpos($_SESSION['RF']["subfolder"],"/") !== 0
    -&& strpos($_SESSION['RF']["subfolder"],'.') === FALSE)
    +if (!empty($_SESSION['RF']["subfolder"]) 
    +	&& strpos($_SESSION['RF']["subfolder"],"/") !== 0
    +	&& strpos($_SESSION['RF']["subfolder"],'.') === FALSE
    +)
     {
     	$rfm_subfolder = $_SESSION['RF']['subfolder'];
     }
    @@ -257,7 +251,7 @@
     	$ext_tmp = array();
     	foreach($extensions as $extension){
     		$extension = fix_strtolower($extension);
    -		if(in_array( $extension, $config['ext'])){
    +		if(check_file_extension( $extension, $config)){
     			$ext_tmp[]=$extension;
     		}
     	}
    @@ -482,6 +476,7 @@
     	<input type="hidden" id="lang_error_upload" value="<?php echo trans('Error_Upload');?>" />
     	<input type="hidden" id="lang_select" value="<?php echo trans('Select');?>" />
     	<input type="hidden" id="lang_extract" value="<?php echo trans('Extract');?>" />
    +	<input type="hidden" id="extract_files" value="<?php if($config['extract_files']) echo 1; else echo 0;?>" />
     	<input type="hidden" id="transliteration" value="<?php echo $config['transliteration']?"true":"false";?>" />
     	<input type="hidden" id="convert_spaces" value="<?php echo $config['convert_spaces']?"true":"false";?>" />
     	<input type="hidden" id="replace_with" value="<?php echo $config['convert_spaces']? $config['replace_with'] : "";?>" />
    
  • filemanager/execute.php+4 8 modified
    @@ -9,13 +9,9 @@
     	exit;
     }
     
    -if (strpos($_POST['path'],'/')===0
    -	|| strpos($_POST['path'],'../')!==FALSE
    -	|| strpos($_POST['path'],'./')===0
    -	|| strpos($_POST['path'],'..\\')!==FALSE
    -	|| strpos($_POST['path'],'.\\')===0)
    +if (!checkRelativePath($_POST['path']))
     {
    -	response(trans('wrong path'.AddErrorLocation()))->send();
    +	response(trans('wrong path'))->send();
     	exit;
     }
     
    @@ -373,7 +369,7 @@ function returnPaths($_path,$_name,$config){
     
     			// something terribly gone wrong
     			if ($action != 'copy' && $action != 'cut'){
    -				response(trans('wrong action').AddErrorLocation())->send();
    +				response(trans('wrong action'))->send();
     				exit;
     			}
     			if($ftp){
    @@ -514,7 +510,7 @@ function returnPaths($_path,$_name,$config){
     
     			break;
     		default:
    -			response(trans('wrong action').AddErrorLocation())->send();
    +			response(trans('wrong action'))->send();
     			exit;
     	}
     }
    
  • filemanager/force_download.php+3 7 modified
    @@ -12,20 +12,16 @@
     }
     
     
    -if (
    +if (!checkRelativePath($_POST['path']) ||
         strpos($_POST['path'], '/') === 0
    -    || strpos($_POST['path'], '../') !== false
    -    || strpos($_POST['path'], './') === 0
    -    || strpos($_POST['path'], '..\\') !== false
    -    || strpos($_POST['path'], '.\\') === 0
     ) {
    -    response(trans('wrong path' . AddErrorLocation()), 400)->send();
    +    response(trans('wrong path'), 400)->send();
         exit;
     }
     
     
     if (strpos($_POST['name'], '/') !== false) {
    -    response(trans('wrong path' . AddErrorLocation()), 400)->send();
    +    response(trans('wrong path' ), 400)->send();
         exit;
     }
     
    
  • filemanager/include/utils.php+57 3 modified
    @@ -94,6 +94,32 @@ function trans($var)
     	}
     }
     
    +
    +
    +
    +/**
    +* Check relative path
    +*
    +* @param  string  $path
    +*
    +* @return boolean is it correct?
    +*/
    +function checkRelativePath($path){
    +	$path_correct = true;
    +	$path_decoded = rawurldecode($path);
    +	if (strpos($path, '../') !== false
    +        || strpos($path, './') !== false
    +        || strpos($path, '..\\') !== false
    +        || strpos($path, '.\\') !== false
    +    	|| strpos($path_decoded, '../') !== false
    +        || strpos($path_decoded, './') !== false
    +        || strpos($path_decoded, '..\\') !== false
    +        || strpos($path_decoded, '.\\') !== false) {
    +        $path_correct = false;
    +    }
    +    return $path_correct;
    +}
    +
     /**
     * Delete file
     *
    @@ -567,6 +593,34 @@ function check_files_extensions_on_path($path, $ext)
     	}
     }
     
    +
    +/**
    +* Check file extension 
    +*
    +* @param  string  $extension
    +* @param  array   $config
    +*/
    +
    +function check_file_extension($extension,$config){
    +	$check = false;
    +	if (!$config['ext_blacklist']) {
    +		if(in_array(mb_strtolower($extension), $conf['ext'])){
    +			$check = true;
    +		}
    +    } else {
    +    	if(!in_array(mb_strtolower($extension), $conf['ext_blacklist'])){
    +			$check = true;
    +		}
    +    }
    +
    +	if($config['files_without_extension'] && $extension == ''){
    +		$check = true;
    +	}
    +
    +	return $check;
    +}
    +
    +
     /**
     * Get file extension present in PHAR file
     *
    @@ -575,13 +629,13 @@ function check_files_extensions_on_path($path, $ext)
     * @param  string  $basepath
     * @param  string  $ext
     */
    -function check_files_extensions_on_phar($phar, &$files, $basepath, $ext)
    +function check_files_extensions_on_phar($phar, &$files, $basepath, $config)
     {
     	foreach ($phar as $file)
     	{
     		if ($file->isFile())
     		{
    -			if (in_array(mb_strtolower($file->getExtension()), $ext))
    +			if (check_file_extension($file->getExtension()))
     			{
     				$files[] = $basepath . $file->getFileName();
     			}
    @@ -591,7 +645,7 @@ function check_files_extensions_on_phar($phar, &$files, $basepath, $ext)
     			if ($file->isDir())
     			{
     				$iterator = new DirectoryIterator($file);
    -				check_files_extensions_on_phar($iterator, $files, $basepath . $file->getFileName() . '/', $ext);
    +				check_files_extensions_on_phar($iterator, $files, $basepath . $file->getFileName() . '/', $config);
     			}
     		}
     	}
    
  • filemanager/upload.php+2 5 modified
    @@ -34,11 +34,8 @@
     
         $fldr = rawurldecode(trim(strip_tags($_POST['fldr']), "/") . "/");
     
    -    if (strpos($fldr, '../') !== false
    -        || strpos($fldr, './') !== false
    -        || strpos($fldr, '..\\') !== false
    -        || strpos($fldr, '.\\') !== false) {
    -        response(trans('wrong path' . AddErrorLocation()))->send();
    +    if (!checkRelativePath($fldr)) {
    +        response(trans('wrong path'))->send();
             exit;
         }
     
    
  • gulpfile.js+0 5 modified
    @@ -88,9 +88,4 @@ elixir(function (mix) {
             ['modernizr.custom.js'],
             'filemanager/js/modernizr.custom.js'
         );
    -
    -    mix.scripts(
    -        ['load_more.js'],
    -        'filemanager/js/load_more.js'
    -    );
     });
    
  • resources/assets/js/include.js+10 9 modified
    @@ -3,7 +3,7 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     {
     	"use strict";
     
    -	var version = "9.13.3";
    +	var version = "9.13.4";
     	var active_contextmenu = true;
     	var myLazyLoad = null;
     	var clipboard = null;
    @@ -239,9 +239,10 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     						disabled: false
     					};
     					// extract
    -					if ($trigger.find('.img-precontainer-mini .filetype').hasClass('zip') ||
    +					if (($trigger.find('.img-precontainer-mini .filetype').hasClass('zip') ||
     						$trigger.find('.img-precontainer-mini .filetype').hasClass('tar') ||
    -						$trigger.find('.img-precontainer-mini .filetype').hasClass('gz'))
    +						$trigger.find('.img-precontainer-mini .filetype').hasClass('gz')) && 
    +						jQuery('#extract_files').val() == 1)
     					{
     						options.items.unzip = {
     							name: jQuery('#lang_extract').val(),
    @@ -840,7 +841,7 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     		// info btn
     		jQuery('#info').on('click', function ()
     		{
    -			bootbox.alert('<div class="text-center"><br/><img src="img/logo.png" alt="responsive filemanager"/><br/><br/><p><strong>RESPONSIVE filemanager v.' + version + '</strong><br/><a href="http://www.responsivefilemanager.com">responsivefilemanager.com</a></p><br/><p>Copyright © <a href="http://www.tecrail.com" alt="tecrail">Tecrail</a> - Alberto Peripolli. All rights reserved.</p><br/><p>License<br/><small><img alt="Creative Commons License" style="border-width:0" src="http://responsivefilemanager.com/license.php" /><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc/3.0/">Creative Commons Attribution-NonCommercial 3.0 Unported License</a>.</small></p></div>');
    +			bootbox.alert('<div class="text-center"><br/><img src="img/logo.png" alt="responsive filemanager"/><br/><br/><p><strong>RESPONSIVE filemanager v.' + version + '</strong><br/><a href="http://www.responsivefilemanager.com">responsivefilemanager.com</a></p><br/><p>Copyright © <a href="http://www.tecrail.com" alt="tecrail">Tecrail</a> - Alberto Peripolli. All rights reserved.</p><br/><p>License<br/><small><img alt="Creative Commons License" style="border-width:0" src="https://www.responsivefilemanager.com/license.php" /><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc/3.0/">Creative Commons Attribution-NonCommercial 3.0 Unported License</a>.</small></p></div>');
     		});
     
     		jQuery('#change_lang_btn').on('click', function ()
    @@ -982,11 +983,10 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     		});
     		var getFiles = function(path){
     			var files = [];
    -			var subdir = jQuery('#subdir').val();
     			jQuery('.selection:checkbox:checked:visible').each(function () {
     				var file = jQuery(this).val();
     				if(path){
    -					file = subdir + file;
    +					file = jQuery(this).closest('figure').attr('data-path');
     				}
     				files.push(file);
     			});
    @@ -1017,6 +1017,7 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     				if (result == true)
     				{
     					var files = getFiles(true);
    +
     					execute_multiple_action('delete_files', files, '', '', '');
     					var fil = jQuery('#files_number');
     					fil.text(parseInt(fil.text())-files.length);
    @@ -1752,8 +1753,8 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     	function returnUrls(files){
     		var path = jQuery('#cur_dir').val();
     		path = path.replace('\\', '/');
    -		var subdir = jQuery('#subdir').val();
    -		subdir = subdir.replace('\\', '/');
    +		var sub_folder = jQuery('#sub_folder').val();
    +		sub_folder = sub_folder.replace('\\', '/');
     		var base_url = jQuery('#base_url').val();
     		var urls=[];
     		var is_return_relative_url = jQuery('#return_relative_url').val();
    @@ -1763,7 +1764,7 @@ var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any
     			if(is_ftp){
     				urls.push(encodeURL(jQuery('#ftp_base_url').val() + jQuery('#upload_dir').val() + jQuery('#fldr_value').val() + file));
     			}else{
    -				urls.push(encodeURL((is_return_relative_url == 1 ? subdir : base_url + path) + file));
    +				urls.push(encodeURL((is_return_relative_url == 1 ? sub_folder : base_url + path) + file));
     			}
     		}
     		return urls;
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.