CVE-2024-29272 (PHP, published 2024-03-22T04:15Z)
Description: value: Arbitrary File Upload vulnerability in VvvebJs before version 1.7.5, allows unauthenticated remote attackers to execute arbitrary code and obtain sensitive information via the sanitizeFileName parameter in save.php.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/givanz/VvvebJs
Files changed:
save.php
scan.php
upload.php
Commit message: Fixed vulnerabilities reported by João Victor https://github.com/givanz/VvvebJs/issues/339


Vulnerable code:
	$file = __DIR__ . '/' . preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
	$html = file_get_contents($startTemplateUrl);
	$file = sanitizeFileName($_POST['file'], false);
			$newfile = sanitizeFileName($_POST['newfile'], false);
				$dir = dirname($file);
				if (!is_dir($dir)) {
					echo "$dir folder does not exist\n";
					if (mkdir($dir, 0777, true)) {
						echo "$dir folder was created\n";
						showError("Error creating folder '$dir'\n");
					}				
				}
				
				if (file_put_contents($file, $html)) {
					echo "File saved '$file'";
					showError("Error saving file '$file'\nPossible causes are missing write permission or incorrect file path!");
			header('Content-Type: application/json');
			echo file_get_contents($_GET['url']);
if (isset($_POST['mediaPath'])) {
	define('UPLOAD_PATH', $_POST['mediaPath']);
$scandir = __DIR__ . '/' . UPLOAD_PATH;
$uploadAllowExtensions = ['ico','jpg','jpeg','png','gif','webp'];

define('UPLOAD_FOLDER', __DIR__ . '/');
	define('UPLOAD_PATH', sanitizeFileName($_POST['mediaPath']) .'/');
	define('UPLOAD_PATH', '/');
$fileName  = $_FILES['file']['name'];
/*
*/
$destination = UPLOAD_FOLDER . UPLOAD_PATH . '/' . $fileName;

Fixed code:
define('ALLOW_PHP', false);//check if saved html contains php tag and don't save if not allowed
define('ALLOWED_OEMBED_DOMAINS', [
	'https://www.youtube.com/', 
	'https://www.vimeo.com/', 
	'https://www.twitter.com/'
]);//load urls only from allowed websites for oembed
	$basename = basename($file);
	$disallow = ['.htaccess', 'passwd'];
	if (in_array($basename, $disallow)) {
		showError('Filename not allowed!');
		return '';
	}
	
	$file = preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
	
	if ($file) {
		$file = __DIR__ . DIRECTORY_SEPARATOR . $file;
	} else {
		return '';
	}
function validOembedUrl($url) {
	foreach (ALLOWED_OEMBED_DOMAINS as $domain) {
		if (strpos($url, $domain) === 0) {
			return true;
		}
	}
	
	return false;
}

	$html = '';
	if ($startTemplateUrl) {
		$html = file_get_contents($startTemplateUrl);
	}
	if (!ALLOW_PHP) {
		//if (strpos($html, '<?php') !== false) {
		if (preg_match('@<\?php|<\? |<\?=|<\s*script\s*language\s*=\s*"\s*php\s*"\s*>@', $html)) {
			showError('PHP not allowed!');
		}
	}
	$file = sanitizeFileName($_POST['file']);
			$newfile = sanitizeFileName($_POST['newfile']);
				if ($file) {
					$dir = dirname($file);
					if (!is_dir($dir)) {
						echo "$dir folder does not exist\n";
						if (mkdir($dir, 0777, true)) {
							echo "$dir folder was created\n";
						} else {
							showError("Error creating folder '$dir'\n");
						}				
					}
					
					if (file_put_contents($file, $html)) {
						echo "File saved '$file'";
						showError("Error saving file '$file'\nPossible causes are missing write permission or incorrect file path!");
					}
					showError('Invalid filename!');
			$url = $_GET['url'] ?? '';
			if (validOembedUrl($url)) {
				header('Content-Type: application/json');
				echo file_get_contents($url);
			} else {
				showError('Invalid url!');
			}
function sanitizePath($path) {
	//sanitize, remove double dot .. and remove get parameters if any
	$path = preg_replace('@/+@' , DIRECTORY_SEPARATOR, preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $path))));
	return $path;
}

if (isset($_POST['mediaPath']) && ($path = sanitizePath(substr($_POST['mediaPath'], 0, 256)))) {
	define('UPLOAD_PATH', $path);
$scandir = __DIR__ . DIRECTORY_SEPARATOR. UPLOAD_PATH;
$uploadAllowExtensions = ['ico','jpg','jpeg','png','gif','webp','svg'];
	$disallow = ['.htaccess', 'passwd'];
	$file = str_replace($disallow, '', $file);
	
	
define('UPLOAD_FOLDER', __DIR__ . DIRECTORY_SEPARATOR);
	define('UPLOAD_PATH', sanitizeFileName($_POST['mediaPath']) . DIRECTORY_SEPARATOR);
	define('UPLOAD_PATH', DIRECTORY_SEPARATOR);
}

$fileName  = sanitizeFileName($_FILES['file']['name']);
if (!$fileName) {
	showError('Invalid filename!');
$destination = UPLOAD_FOLDER . UPLOAD_PATH . DIRECTORY_SEPARATOR . $fileName;