CVE-2018-17057: Deserialization of Untrusted Data (CWE-502)
value: An issue was discovered in TCPDF before 6.2.22. Attackers can trigger deserialization of arbitrary data via the phar:// wrapper.
CWE description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
CVSS v3 base score: 9.8
Published: 2018-09-14T20:29Z
Repository: https://github.com/tecnickcom/TCPDF
Language: PHP
Files changed: CHANGELOG.TXT, composer.json, include/tcpdf_fonts.php, include/tcpdf_images.php, include/tcpdf_static.php, tcpdf.php
Commit date: 2018-09-14 14:28:55 +0100
Commit message: Fix for security vulnerability: Using the phar:// wrapper it was possible to trigger the unserialization of user provided data.

Diff: diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT
index 88658e6..fc0bb41 100644
--- a/CHANGELOG.TXT
+++ b/CHANGELOG.TXT
@@ -1,5 +1,8 @@
+6.2.20
+	- Fix for security vulnerability: Using the phar:// wrapper it was possible to trigger the unserialization of user provided data.
+
 6.2.19
 	- Merge various fixes for PHP 7.3 compatibility and security.
 
 6.2.13 (2016-06-10)
 	- IMPORTANT: A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this version will not receive any additional development or support. This version should be considered obsolete, new projects should use the new version as soon it will become stable.
diff --git a/composer.json b/composer.json
index 3a6d1c3..c162aba 100644
--- a/composer.json
+++ b/composer.json
@@ -1,8 +1,8 @@
 {
   "name": "tecnickcom/tcpdf",
-  "version": "6.2.19",
+  "version": "6.2.20",
   "homepage": "http://www.tcpdf.org/",
   "type": "library",
   "description": "TCPDF is a PHP class for generating PDF documents and barcodes.",
   "keywords": [
     "PDF",
diff --git a/include/tcpdf_fonts.php b/include/tcpdf_fonts.php
index ba89c7c..211a236 100644
--- a/include/tcpdf_fonts.php
+++ b/include/tcpdf_fonts.php
@@ -68,11 +68,11 @@ class TCPDF_FONTS {
 	 * @author Nicola Asuni
 	 * @since 5.9.123 (2010-09-30)
 	 * @public static
 	 */
 	public static function addTTFfont($fontfile, $fonttype='', $enc='', $flags=32, $outpath='', $platid=3, $encid=1, $addcbbox=false, $link=false) {
-		if (!file_exists($fontfile)) {
+		if (!TCPDF_STATIC::file_exists($fontfile)) {
 			// Could not find file
 			return false;
 		}
 		// font metrics
 		$fmetric = array();
@@ -93,11 +93,11 @@ class TCPDF_FONTS {
 		// set output path
 		if (empty($outpath)) {
 			$outpath = self::_getfontpath();
 		}
 		// check if this font already exist
-		if (@file_exists($outpath.$font_name.'.php')) {
+		if (@TCPDF_STATIC::file_exists($outpath.$font_name.'.php')) {
 			// this font already exist (delete it from fonts folder to rebuild it)
 			return $font_name;
 		}
 		$fmetric['file'] = $font_name;
 		$fmetric['ctg'] = $font_name.'.ctg.z';
@@ -1541,15 +1541,15 @@ class TCPDF_FONTS {
 	 * @public static
 	 */
 	public static function getFontFullPath($file, $fontdir=false) {
 		$fontfile = '';
 		// search files on various directories
-		if (($fontdir !== false) AND @file_exists($fontdir.$file)) {
+		if (($fontdir !== false) AND @TCPDF_STATIC::file_exists($fontdir.$file)) {
 			$fontfile = $fontdir.$file;
-		} elseif (@file_exists(self::_getfontpath().$file)) {
+		} elseif (@TCPDF_STATIC::file_exists(self::_getfontpath().$file)) {
 			$fontfile = self::_getfontpath().$file;
-		} elseif (@file_exists($file)) {
+		} elseif (@TCPDF_STATIC::file_exists($file)) {
 			$fontfile = $file;
 		}
 		return $fontfile;
 	}
 
diff --git a/include/tcpdf_images.php b/include/tcpdf_images.php
index c2e3c36..cf2ce0d 100644
--- a/include/tcpdf_images.php
+++ b/include/tcpdf_images.php
@@ -159,14 +159,14 @@ class TCPDF_IMAGES {
 	 * @return array structure containing the image data
 	 * @public static
 	 */
 	public static function _parsejpeg($file) {
 		// check if is a local file
-		if (!@file_exists($file)) {
+		if (!@TCPDF_STATIC::file_exists($file)) {
 			// try to encode spaces on filename
 			$tfile = str_replace(' ', '%20', $file);
-			if (@file_exists($tfile)) {
+			if (@TCPDF_STATIC::file_exists($tfile)) {
 				$file = $tfile;
 			}
 		}
 		$a = getimagesize($file);
 		if (empty($a)) {
diff --git a/include/tcpdf_static.php b/include/tcpdf_static.php
index 166f5f9..b230a02 100644
--- a/include/tcpdf_static.php
+++ b/include/tcpdf_static.php
@@ -53,11 +53,11 @@ class TCPDF_STATIC {
 
 	/**
 	 * Current TCPDF version.
 	 * @private static
 	 */
-	private static $tcpdf_version = '6.2.19';
+	private static $tcpdf_version = '6.2.20';
 
 	/**
 	 * String alias for total number of pages.
 	 * @public static
 	 */
@@ -1852,10 +1852,33 @@ class TCPDF_STATIC {
 			return false;
 		}
 		return fopen($filename, $mode);
 	}
 
+	/**
+	 * Wrapper for file_exists.
+	 * Checks whether a file or directory exists.
+	 * Only allows some protocols and local files.
+	 * @param filename (string) Path to the file or directory. 
+	 * @return Returns TRUE if the file or directory specified by filename exists; FALSE otherwise.  
+	 * @public static
+	 */
+	public static function file_exists($filename) {
+		if (strpos($filename, '://') > 0) {
+			$wrappers = stream_get_wrappers();
+			foreach ($wrappers as $wrapper) {
+				if (($wrapper === 'http') || ($wrapper === 'https')) {
+					continue;
+				}
+				if (stripos($filename, $wrapper.'://') === 0) {
+					return false;
+				}
+			}
+		}
+		return @file_exists($filename);
+	}
+
 	/**
 	 * Reads entire file into a string.
 	 * The file can be also an URL.
 	 * @param $file (string) Name of the file or URL to read.
 	 * @return The function returns the read data or FALSE on failure. 
@@ -1912,12 +1935,14 @@ class TCPDF_STATIC {
 		    $urldata = @parse_url($_SERVER['SCRIPT_URI']);
 		    $alt[] = $urldata['scheme'].'://'.$urldata['host'].(($file[0] == '/') ? '' : '/').$file;
 		}
 		//
 		$alt = array_unique($alt);
-		//var_dump($alt);exit;//DEBUG
 		foreach ($alt as $path) {
+			if (!self::file_exists($path)) {
+				return false;
+			}
 			$ret = @file_get_contents($path);
 			if ($ret !== false) {
 			    return $ret;
 			}
 			// try to use CURL for URLs
@@ -1947,12 +1972,10 @@ class TCPDF_STATIC {
 			}
 		}
 		return false;
 	}
 
-    
-
 	/**
 	 * Get ULONG from string (Big Endian 32-bit unsigned integer).
 	 * @param $str (string) string from where to extract value
 	 * @param $offset (int) point from where to read the data
 	 * @return int 32 bit value
diff --git a/tcpdf.php b/tcpdf.php
index 2c3f629..bcefe52 100644
--- a/tcpdf.php
+++ b/tcpdf.php
@@ -1,9 +1,9 @@
 <?php
 //============================================================+
 // File name   : tcpdf.php
-// Version     : 6.2.19
+// Version     : 6.2.20
 // Begin       : 2002-08-03
 // Last Update : 2018-09-14
 // Author      : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
 // License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
 // -------------------------------------------------------------------
@@ -102,11 +102,11 @@
  * <li>PDF/A-1b support.</li>
  * </ul>
  * Tools to encode your unicode fonts are on fonts/utils directory.</p>
  * @package com.tecnick.tcpdf
  * @author Nicola Asuni
- * @version 6.2.19
+ * @version 6.2.20
  */
 
 // TCPDF configuration
 require_once(dirname(__FILE__).'/tcpdf_autoconfig.php');
 // TCPDF static font methods and data
@@ -126,11 +126,11 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php');
  * @class TCPDF
  * PHP class for generating PDF documents without requiring external extensions.
  * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br>
  * @package com.tecnick.tcpdf
  * @brief PHP class for generating PDF documents without requiring external extensions.
- * @version 6.2.19
+ * @version 6.2.20
  * @author Nicola Asuni - info@tecnick.com
  * @IgnoreAnnotation("protected")
  * @IgnoreAnnotation("public")
  * @IgnoreAnnotation("pre")
  */
@@ -4254,11 +4254,11 @@ class TCPDF {
 			}
 		}
 		// true when the font style variation is missing
 		$missing_style = false;
 		// search and include font file
-		if (TCPDF_STATIC::empty_string($fontfile) OR (!@file_exists($fontfile))) {
+		if (TCPDF_STATIC::empty_string($fontfile) OR (!@TCPDF_STATIC::file_exists($fontfile))) {
 			// build a standard filenames for specified font
 			$tmp_fontfile = str_replace(' ', '', $family).strtolower($style).'.php';
 			$fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);
 			if (TCPDF_STATIC::empty_string($fontfile)) {
 				$missing_style = true;
@@ -4266,11 +4266,11 @@ class TCPDF {
 				$tmp_fontfile = str_replace(' ', '', $family).'.php';
 				$fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);
 			}
 		}
 		// include font file
-		if (!TCPDF_STATIC::empty_string($fontfile) AND (@file_exists($fontfile))) {
+		if (!TCPDF_STATIC::empty_string($fontfile) AND (@TCPDF_STATIC::file_exists($fontfile))) {
 			include($fontfile);
 		} else {
 			$this->Error('Could not include font definition file: '.$family.'');
 		}
 		// check font parameters
@@ -4807,23 +4807,23 @@ class TCPDF {
 			$this->PageAnnots[$page] = array();
 		}
 		$this->PageAnnots[$page][] = array('n' => ++$this->n, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'txt' => $text, 'opt' => $opt, 'numspaces' => $spaces);
 		if (!$this->pdfa_mode) {
 			if ((($opt['Subtype'] == 'FileAttachment') OR ($opt['Subtype'] == 'Sound')) AND (!TCPDF_STATIC::empty_string($opt['FS']))
-				AND (@file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
+				AND (@TCPDF_STATIC::file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
 				AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) {
 				$this->embeddedfiles[basename($opt['FS'])] = array('f' => ++$this->n, 'n' => ++$this->n, 'file' => $opt['FS']);
 			}
 		}
 		// Add widgets annotation's icons
-		if (isset($opt['mk']['i']) AND @file_exists($opt['mk']['i'])) {
+		if (isset($opt['mk']['i']) AND @TCPDF_STATIC::file_exists($opt['mk']['i'])) {
 			$this->Image($opt['mk']['i'], '', '', 10, 10, '', '', '', false, 300, '', false, false, 0, false, true);
 		}
-		if (isset($opt['mk']['ri']) AND @file_exists($opt['mk']['ri'])) {
+		if (isset($opt['mk']['ri']) AND @TCPDF_STATIC::file_exists($opt['mk']['ri'])) {
 			$this->Image($opt['mk']['ri'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
 		}
-		if (isset($opt['mk']['ix']) AND @file_exists($opt['mk']['ix'])) {
+		if (isset($opt['mk']['ix']) AND @TCPDF_STATIC::file_exists($opt['mk']['ix'])) {
 			$this->Image($opt['mk']['ix'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
 		}
 	}
 
 	/**
@@ -6843,24 +6843,15 @@ class TCPDF {
 			if ($file[0] === '*') {
 				// image as external stream
 				$file = substr($file, 1);
 				$exurl = $file;
 			}
-			$wrappers = stream_get_wrappers();
-			foreach ($wrappers as $wrapper) {
-				if ($wrapper === 'http' || $wrapper === 'https') {
-					continue;
-				}
-				if (stripos($file, $wrapper.'://') === 0) {
-					$this->Error('Stream wrappers in file paths are not supported');
-				}
-			}
 			// check if is a local file
-			if (!@file_exists($file)) {
+			if (!@TCPDF_STATIC::file_exists($file)) {
 				// try to encode spaces on filename
 				$tfile = str_replace(' ', '%20', $file);
-				if (@file_exists($tfile)) {
+				if (@TCPDF_STATIC::file_exists($tfile)) {
 					$file = $tfile;
 				}
 			}
 			if (($imsize = @getimagesize($file)) === FALSE) {
 				if (in_array($file, $this->imagekeys)) {

Vulnerable code:   "version": "6.2.19",
		if (!file_exists($fontfile)) {
		if (@file_exists($outpath.$font_name.'.php')) {
		if (($fontdir !== false) AND @file_exists($fontdir.$file)) {
		} elseif (@file_exists(self::_getfontpath().$file)) {
		} elseif (@file_exists($file)) {
		if (!@file_exists($file)) {
			if (@file_exists($tfile)) {
	private static $tcpdf_version = '6.2.19';
		//var_dump($alt);exit;//DEBUG
    

// Version     : 6.2.19
 * @version 6.2.19
 * @version 6.2.19
		if (TCPDF_STATIC::empty_string($fontfile) OR (!@file_exists($fontfile))) {
		if (!TCPDF_STATIC::empty_string($fontfile) AND (@file_exists($fontfile))) {
				AND (@file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
		if (isset($opt['mk']['i']) AND @file_exists($opt['mk']['i'])) {
		if (isset($opt['mk']['ri']) AND @file_exists($opt['mk']['ri'])) {
		if (isset($opt['mk']['ix']) AND @file_exists($opt['mk']['ix'])) {
			$wrappers = stream_get_wrappers();
			foreach ($wrappers as $wrapper) {
				if ($wrapper === 'http' || $wrapper === 'https') {
					continue;
				}
				if (stripos($file, $wrapper.'://') === 0) {
					$this->Error('Stream wrappers in file paths are not supported');
				}
			}
			if (!@file_exists($file)) {
				if (@file_exists($tfile)) {
Fixed code: 6.2.20
	- Fix for security vulnerability: Using the phar:// wrapper it was possible to trigger the unserialization of user provided data.

  "version": "6.2.20",
		if (!TCPDF_STATIC::file_exists($fontfile)) {
		if (@TCPDF_STATIC::file_exists($outpath.$font_name.'.php')) {
		if (($fontdir !== false) AND @TCPDF_STATIC::file_exists($fontdir.$file)) {
		} elseif (@TCPDF_STATIC::file_exists(self::_getfontpath().$file)) {
		} elseif (@TCPDF_STATIC::file_exists($file)) {
		if (!@TCPDF_STATIC::file_exists($file)) {
			if (@TCPDF_STATIC::file_exists($tfile)) {
	private static $tcpdf_version = '6.2.20';
	/**
	 * Wrapper for file_exists.
	 * Checks whether a file or directory exists.
	 * Only allows some protocols and local files.
	 * @param filename (string) Path to the file or directory. 
	 * @return Returns TRUE if the file or directory specified by filename exists; FALSE otherwise.  
	 * @public static
	 */
	public static function file_exists($filename) {
		if (strpos($filename, '://') > 0) {
			$wrappers = stream_get_wrappers();
			foreach ($wrappers as $wrapper) {
				if (($wrapper === 'http') || ($wrapper === 'https')) {
					continue;
				}
				if (stripos($filename, $wrapper.'://') === 0) {
					return false;
				}
			}
		}
		return @file_exists($filename);
	}

			if (!self::file_exists($path)) {
				return false;
			}
// Version     : 6.2.20
 * @version 6.2.20
 * @version 6.2.20
		if (TCPDF_STATIC::empty_string($fontfile) OR (!@TCPDF_STATIC::file_exists($fontfile))) {
		if (!TCPDF_STATIC::empty_string($fontfile) AND (@TCPDF_STATIC::file_exists($fontfile))) {
				AND (@TCPDF_STATIC::file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
		if (isset($opt['mk']['i']) AND @TCPDF_STATIC::file_exists($opt['mk']['i'])) {
		if (isset($opt['mk']['ri']) AND @TCPDF_STATIC::file_exists($opt['mk']['ri'])) {
		if (isset($opt['mk']['ix']) AND @TCPDF_STATIC::file_exists($opt['mk']['ix'])) {
			if (!@TCPDF_STATIC::file_exists($file)) {
				if (@TCPDF_STATIC::file_exists($tfile)) {