Skip to content

Commit e237309

Browse files
committed
Security Patch Control Characters in Protocol
1 parent 7af20c3 commit e237309

File tree

11 files changed

+464
-136
lines changed

11 files changed

+464
-136
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com)
66
and this project adheres to [Semantic Versioning](https://semver.org).
77

8+
# TBD - 2.3.7
9+
10+
### Fixed
11+
12+
- Backported security patch for control characters in protocol.
13+
- Use Composer\Pcre in Xls/Parser. Partial backport of [PR #4203](https://github.com/PHPOffice/PhpSpreadsheet/pull/4203)
14+
815
# 2025-01=11 - 2.3.6
916

1017
### Deprecated

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"ext-xmlwriter": "*",
8080
"ext-zip": "*",
8181
"ext-zlib": "*",
82+
"composer/pcre": "^3.2",
8283
"maennchen/zipstream-php": "^2.1 || ^3.0",
8384
"markbaker/complex": "^3.0",
8485
"markbaker/matrix": "^3.0",

composer.lock

Lines changed: 80 additions & 80 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ includes:
22
- phpstan-baseline.neon
33
- vendor/phpstan/phpstan-phpunit/extension.neon
44
- vendor/phpstan/phpstan-phpunit/rules.neon
5+
- vendor/composer/pcre/extension.neon
56

67
parameters:
78
level: 8

src/PhpSpreadsheet/Reader/Html.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,10 @@ private function insertImage(Worksheet $sheet, string $column, int $row, array $
10451045
$name = $attributes['alt'] ?? null;
10461046

10471047
$drawing = new Drawing();
1048-
$drawing->setPath($src);
1048+
$drawing->setPath($src, false);
1049+
if ($drawing->getPath() === '') {
1050+
return;
1051+
}
10491052
$drawing->setWorksheet($sheet);
10501053
$drawing->setCoordinates($column . $row);
10511054
$drawing->setOffsetX(0);

src/PhpSpreadsheet/Worksheet/Drawing.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip
103103

104104
$this->path = '';
105105
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
106-
if (filter_var($path, FILTER_VALIDATE_URL)) {
106+
if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\\w\\s\\x00-\\x1f]+):/u', $path) && !preg_match('/^([\\w]+):/u', $path))) {
107107
if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) {
108108
throw new PhpSpreadsheetException('Invalid protocol for linked drawing');
109109
}

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,9 +1528,10 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
15281528
$url = $worksheet->getHyperlink($coordinate)->getUrl();
15291529
$urlDecode1 = html_entity_decode($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
15301530
$urlTrim = preg_replace('/^\\s+/u', '', $urlDecode1) ?? $urlDecode1;
1531-
$parseScheme = preg_match('/^([\\w\\s]+):/u', strtolower($urlTrim), $matches);
1532-
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 's3'], true)) {
1531+
$parseScheme = preg_match('/^([\\w\\s\\x00-\\x1f]+):/u', strtolower($urlTrim), $matches);
1532+
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 'mailto', 's3'], true)) {
15331533
$cellData = htmlspecialchars($url, Settings::htmlEntityFlags());
1534+
$cellData = self::replaceControlChars($cellData);
15341535
} else {
15351536
$cellData = '<a href="' . htmlspecialchars($url, Settings::htmlEntityFlags()) . '" title="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getTooltip(), Settings::htmlEntityFlags()) . '">' . $cellData . '</a>';
15361537
}
@@ -1580,6 +1581,20 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
15801581
return $html;
15811582
}
15821583

1584+
private static function replaceNonAscii(array $matches): string
1585+
{
1586+
return '&#' . mb_ord($matches[0], 'UTF-8') . ';';
1587+
}
1588+
1589+
private static function replaceControlChars(string $convert): string
1590+
{
1591+
return (string) preg_replace_callback(
1592+
'/[\\x00-\\x1f]/',
1593+
[self::class, 'replaceNonAscii'],
1594+
$convert
1595+
);
1596+
}
1597+
15831598
/**
15841599
* Takes array where of CSS properties / values and converts to CSS string.
15851600
*/

0 commit comments

Comments
 (0)