CVE-2018-17057 (PHP, published 2018-09-14T20:29Z)
Description: value: An issue was discovered in TCPDF before 6.2.22. Attackers can trigger deserialization of arbitrary data via the phar:// wrapper.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-502 \u2014 Deserialization of Untrusted Data
The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
Repository: https://github.com/LimeSurvey/LimeSurvey
Files changed:
application/third_party/tcpdf/CHANGELOG.TXT
application/third_party/tcpdf/LIMESURVEY-README.txt
application/third_party/tcpdf/composer.json
application/third_party/tcpdf/include/tcpdf_fonts.php
application/third_party/tcpdf/include/tcpdf_images.php
application/third_party/tcpdf/include/tcpdf_static.php
application/third_party/tcpdf/tcpdf.php
application/third_party/tcpdf/tcpdf_autoconfig.php
Commit message: [security] Fixed issue #14670 : update tcpdf to 6.2.25
Dev: security fix in 6.2.22


Vulnerable code:
Unreleased
	- fix Undesired mouseover effect on links in PDF on Chrome Pdf Viewer
  "version": "6.2.16",
		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)) {
		$currentfont['subsetchars'] += array_fill_keys($carr, true);
		if (!@file_exists($file)) {
			// try to encode spaces on filename
			$tfile = str_replace(' ', '%20', $file);
			if (@file_exists($tfile)) {
				$file = $tfile;
			}
	private static $tcpdf_version = '6.2.16';
















// ====================================================================================================================
// REIMPLEMENTED
// ====================================================================================================================














		//var_dump($alt);exit;//DEBUG
    

// Version     : 6.2.13
// Last Update : 2015-06-18
// Copyright (C) 2002-2015 Nicola Asuni - Tecnick.com LTD
 * @version 6.2.8
 * @version 6.2.8
	 * 
	 * 
		// restore internal encoding
		if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) {
			mb_internal_encoding($this->internal_encoding);
		}
		if (TCPDF_STATIC::empty_string($fontfile) OR (!@file_exists($fontfile))) {
		if (!TCPDF_STATIC::empty_string($fontfile) AND (@file_exists($fontfile))) {
	 * @param $page (int) Number of target page; -1 indicates the current page (default value). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. 
				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'])) {
			$this->SetY($y);
		} else {
			$y = $this->GetY();
					$this->selectColumn($column);
					$this->selectColumn($column);
					$this->selectColumn($column);
			// check if is a local file
			if (!@file_exists($file)) {
				// try to encode spaces on filename
				$tfile = str_replace(' ', '%20', $file);
				if (@file_exists($tfile)) {
					$file = $tfile;
				}
					$annots .= ' /Contents '.$this->_textstring($pl['txt'], $annot_obj_id);
							if (is_string($pl['txt'])) {
		// if required, add standard sRGB_IEC61966-2.1 blackscaled ICC colour profile
			if ($this->sign AND isset($this->signature_data['cert_type']) 
        foreach($prop as $key => $val) {
	public function write1DBarcode($code, $type, $x='', $y='', $w='', $h='', $xres='', $style='', $align='') {
	public function write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style='', $align='', $distort=false) {
					foreach($attr_array[1] as $id => $name) {
				$this->lMargin += $this->cell_padding['R'];
				$this->rMargin += $this->cell_padding['L'];
									$epsposend = strpos($pmid, $this->epsmarker.'Q', $offset);				
												continue;
				if ((!$this->premode) AND $this->isRTLTextDir()) {
						if ($this->isRTLTextDir()) {
				if (!empty($tag['attribute']['src'])) {
					if ($tag['attribute']['src'][0] === '@') {
						// data stream
						$tag['attribute']['src'] = '@'.base64_decode(substr($tag['attribute']['src'], 1));
						$type = '';
					} else {
						// get image type
						$type = TCPDF_IMAGES::getImageFileType($tag['attribute']['src']);
					}
					if (!isset($tag['width'])) {
						$tag['width'] = 0;
					}
					if (!isset($tag['height'])) {
						$tag['height'] = 0;
					}
					//if (!isset($tag['attribute']['align'])) {
						// the only alignment supported is "bottom"
						// further development is required for other modes.
						$tag['attribute']['align'] = 'bottom';
					//}
					switch($tag['attribute']['align']) {
						case 'top': {
							$align = 'T';
							break;
						}
						case 'middle': {
							$align = 'M';
							break;
						}
						case 'bottom': {
							$align = 'B';
							break;
						default: {
							$align = 'B';
							break;
					$prevy = $this->y;
					$xpos = $this->x;
					$imglink = '';
					if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) {
						$imglink = $this->HREF['url'];
						if ($imglink[0] == '#') {
							// convert url to internal link
							$lnkdata = explode(',', $imglink);
							if (isset($lnkdata[0])) {
								$page = intval(substr($lnkdata[0], 1));
								if (empty($page) OR ($page <= 0)) {
									$page = $this->page;
								}
								if (isset($lnkdata[1]) AND (strlen($lnkdata[1]) > 0)) {
									$lnky = floatval($lnkdata[1]);
								} else {
									$lnky = 0;
								}
								$imglink = $this->AddLink();
								$this->SetLink($imglink, $lnky, $page);
					$border = 0;
					if (isset($tag['border']) AND !empty($tag['border'])) {
						// currently only support 1 (frame) or a combination of 'LTRB'
						$border = $tag['border'];
					}
					$iw = '';
					if (isset($tag['width'])) {
						$iw = $this->getHTMLUnitToUnits($tag['width'], ($tag['fontsize'] / $this->k), 'px', false);
					}
					$ih = '';
					if (isset($tag['height'])) {
						$ih = $this->getHTMLUnitToUnits($tag['height'], ($tag['fontsize'] / $this->k), 'px', false);
					}
					if (($type == 'eps') OR ($type == 'ai')) {
						$this->ImageEps($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, true, $align, '', $border, true);
					} elseif ($type == 'svg') {
						$this->ImageSVG($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, $align, '', $border, true);
					} else {
						$this->Image($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border, false, false, true);
					switch($align) {
						case 'T': {
							$this->y = $prevy;
							break;
						}
						case 'M': {
							$this->y = (($this->img_rb_y + $prevy - ($this->getCellHeight($tag['fontsize'] / $this->k))) / 2);
							break;
						}
						case 'B': {
							$this->y = $this->img_rb_y - ($this->getCellHeight($tag['fontsize'] / $this->k) - ($this->getFontDescent($tag['fontname'], $tag['fontstyle'], $tag['fontsize']) * $this->cell_height_ratio));
							break;
						}
				$this->HREF = '';
				if ($templates['F'.$outline['l']]) {
		
						if (!isset($testscrtype['query']) OR empty($testscrtype['query'])) {
			//define ('K_PATH_IMAGES', $tcpdf_images_path);

Fixed code:
6.2.25
	- Fix support for image URLs.

6.2.24
	- Support remote urls when checking if file exists.

6.2.23
	- Simplify file_exists function.

6.2.22
	- 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.
Not updated tcpdf 6.2.25 version. Remove examples directory.
  "version": "6.2.26",
		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 (is_array($currentfont['subsetchars']) && is_array($carr)) {
			$currentfont['subsetchars'] += array_fill_keys($carr, true);
		} else {
			$currentfont['subsetchars'] = array_merge($currentfont['subsetchars'], $carr);
		}
		if (!@TCPDF_STATIC::file_exists($file)) {
			return false;
	private static $tcpdf_version = '6.2.26';
	/**
	 * Check if the URL exist.
	 * @param url (string) URL to check.
	 * @return Returns TRUE if the URL exists; FALSE otherwise.
	 * @public static
	 */
	public static function url_exists($url) {
		$crs = curl_init();
		curl_setopt($crs, CURLOPT_URL, $url);
		curl_setopt($crs, CURLOPT_NOBODY, true);
		curl_setopt($crs, CURLOPT_FAILONERROR, true);
		if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) {
			curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true);
		}
		curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5);
		curl_setopt($crs, CURLOPT_TIMEOUT, 30);
		curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file');
		curl_exec($crs);
		$code = curl_getinfo($crs, CURLINFO_HTTP_CODE);
		curl_close($crs);
		return ($code == 200);
	}

	/**
	 * 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 (preg_match('|^https?://|', $filename) == 1) {
			return self::url_exists($filename);
		}
		if (strpos($filename, '://')) {
			return false; // only support http and https wrappers for security reasons
		}
		return @file_exists($filename);
	}

			if (!self::file_exists($path)) {
				return false;
			}
// Version     : 6.2.26
// Last Update : 2018-09-14
// Copyright (C) 2002-2018 Nicola Asuni - Tecnick.com LTD
 * @version 6.2.26
 * @version 6.2.26
 * @IgnoreAnnotation("protected")
 * @IgnoreAnnotation("public")
 * @IgnoreAnnotation("pre")
	 *
	 *
		if (TCPDF_STATIC::empty_string($fontfile) OR (!@TCPDF_STATIC::file_exists($fontfile))) {
		if (!TCPDF_STATIC::empty_string($fontfile) AND (@TCPDF_STATIC::file_exists($fontfile))) {
		$size = (float)$size;
	 * @param $page (int) Number of target page; -1 indicates the current page (default value). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
				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'])) {
			$this->SetY($y); // set y in order to convert negative y values to positive ones
		$y = $this->GetY();
					if ($column != $this->current_column) {
						$this->selectColumn($column);
					}
					if ($column != $this->current_column) {
						$this->selectColumn($column);
					}
					if ($column != $this->current_column) {
						$this->selectColumn($column);
					}
			// check if file exist and it is valid
			if (!@TCPDF_STATIC::file_exists($file)) {
				return false;
		// restore internal encoding
		if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) {
			mb_internal_encoding($this->internal_encoding);
		}
					if ($pl['opt']['subtype'] !== 'Link') {
						$annots .= ' /Contents '.$this->_textstring($pl['txt'], $annot_obj_id);
					}
							if (is_string($pl['txt']) && !empty($pl['txt'])) {
		// if required, add standard sRGB ICC colour profile
			if ($this->sign AND isset($this->signature_data['cert_type'])
		foreach($prop as $key => $val) {
	public function write1DBarcode($code, $type, $x='', $y='', $w='', $h='', $xres='', $style=array(), $align='') {
	public function write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style=array(), $align='', $distort=false) {
                    foreach($attr_array[1] as $id => $name) {
				$this->lMargin += $this->cell_padding['L'];
				$this->rMargin += $this->cell_padding['R'];
									$epsposend = strpos($pmid, $this->epsmarker.'Q', $offset);
												break;
				$isRTLString = preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $dom[$key]['value']) || preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $dom[$key]['value']);
				if ((!$this->premode) AND $this->isRTLTextDir() AND !$isRTLString) {
						if ($this->isRTLTextDir() AND !$isRTLString) {
				if (empty($tag['attribute']['src'])) {
					break;
				}
				$imgsrc = $tag['attribute']['src'];
				if ($imgsrc[0] === '@') {
					// data stream
					$imgsrc = '@'.base64_decode(substr($imgsrc, 1));
					$type = '';
				} else {
					if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
						// fix image path
						$findroot = strpos($imgsrc, $_SERVER['DOCUMENT_ROOT']);
						if (($findroot === false) OR ($findroot > 1)) {
							if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
								$imgsrc = substr($_SERVER['DOCUMENT_ROOT'], 0, -1).$imgsrc;
							} else {
								$imgsrc = $_SERVER['DOCUMENT_ROOT'].$imgsrc;
							}
						$imgsrc = urldecode($imgsrc);
						$testscrtype = @parse_url($imgsrc);
						if (empty($testscrtype['query'])) {
							// convert URL to server path
							$imgsrc = str_replace(K_PATH_URL, K_PATH_MAIN, $imgsrc);
						} elseif (preg_match('|^https?://|', $imgsrc) !== 1) {
							// convert URL to server path
							$imgsrc = str_replace(K_PATH_MAIN, K_PATH_URL, $imgsrc);
					// get image type
					$type = TCPDF_IMAGES::getImageFileType($imgsrc);
				}
				if (!isset($tag['width'])) {
					$tag['width'] = 0;
				}
				if (!isset($tag['height'])) {
					$tag['height'] = 0;
				}
				//if (!isset($tag['attribute']['align'])) {
					// the only alignment supported is "bottom"
					// further development is required for other modes.
					$tag['attribute']['align'] = 'bottom';
				//}
				switch($tag['attribute']['align']) {
					case 'top': {
						$align = 'T';
						break;
					}
					case 'middle': {
						$align = 'M';
						break;
					}
					case 'bottom': {
						$align = 'B';
						break;
					}
					default: {
						$align = 'B';
						break;
					}
				}
				$prevy = $this->y;
				$xpos = $this->x;
				$imglink = '';
				if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) {
					$imglink = $this->HREF['url'];
					if ($imglink[0] == '#') {
						// convert url to internal link
						$lnkdata = explode(',', $imglink);
						if (isset($lnkdata[0])) {
							$page = intval(substr($lnkdata[0], 1));
							if (empty($page) OR ($page <= 0)) {
								$page = $this->page;
							}
							if (isset($lnkdata[1]) AND (strlen($lnkdata[1]) > 0)) {
								$lnky = floatval($lnkdata[1]);
							} else {
								$lnky = 0;
							$imglink = $this->AddLink();
							$this->SetLink($imglink, $lnky, $page);
				}
				$border = 0;
				if (isset($tag['border']) AND !empty($tag['border'])) {
					// currently only support 1 (frame) or a combination of 'LTRB'
					$border = $tag['border'];
				}
				$iw = '';
				if (isset($tag['width'])) {
					$iw = $this->getHTMLUnitToUnits($tag['width'], ($tag['fontsize'] / $this->k), 'px', false);
				}
				$ih = '';
				if (isset($tag['height'])) {
					$ih = $this->getHTMLUnitToUnits($tag['height'], ($tag['fontsize'] / $this->k), 'px', false);
				}
				if (($type == 'eps') OR ($type == 'ai')) {
					$this->ImageEps($imgsrc, $xpos, $this->y, $iw, $ih, $imglink, true, $align, '', $border, true);
				} elseif ($type == 'svg') {
					$this->ImageSVG($imgsrc, $xpos, $this->y, $iw, $ih, $imglink, $align, '', $border, true);
				} else {
					$this->Image($imgsrc, $xpos, $this->y, $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border, false, false, true);
				}
				switch($align) {
					case 'T': {
						$this->y = $prevy;
						break;
					case 'M': {
						$this->y = (($this->img_rb_y + $prevy - ($this->getCellHeight($tag['fontsize'] / $this->k))) / 2);
						break;
					}
					case 'B': {
						$this->y = $this->img_rb_y - ($this->getCellHeight($tag['fontsize'] / $this->k) - ($this->getFontDescent($tag['fontname'], $tag['fontstyle'], $tag['fontsize']) * $this->cell_height_ratio));
						break;
				$this->HREF = array();
				if (isset($templates['F'.$outline['l']]) && $templates['F'.$outline['l']]) {

						if (empty($testscrtype['query'])) {
						} elseif (preg_match('|^https?://|', $img) !== 1) {
							// convert server path to URL
							$img = str_replace(K_PATH_MAIN, K_PATH_URL, $img);
			define ('K_PATH_IMAGES', $tcpdf_images_path);