diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php
index f73bf53afc..d70a067f6f 100644
--- a/src/PhpSpreadsheet/Writer/Html.php
+++ b/src/PhpSpreadsheet/Writer/Html.php
@@ -403,12 +403,12 @@ public function generateHTMLHeader(bool $includeStyles = false): string
} else {
$propertyValue = (string) $propertyValue;
}
- $html .= self::generateMeta($propertyValue, "custom.$propertyQualifier.$customProperty");
+ $html .= self::generateMeta($propertyValue, htmlspecialchars("custom.$propertyQualifier.$customProperty"));
}
}
if (!empty($properties->getHyperlinkBase())) {
- $html .= ' ' . PHP_EOL;
+ $html .= ' ' . PHP_EOL;
}
$html .= $includeStyles ? $this->generateStyles(true) : $this->generatePageDeclarations(true);
@@ -1586,8 +1586,9 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
// Hyperlink?
if ($worksheet->hyperlinkExists($coordinate) && !$worksheet->getHyperlink($coordinate)->isInternal()) {
$url = $worksheet->getHyperlink($coordinate)->getUrl();
- $urldecode = strtolower(html_entity_decode(trim($url), encoding: 'UTF-8'));
- $parseScheme = preg_match('/^(\\w+):/', $urldecode, $matches);
+ $urlDecode1 = html_entity_decode($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
+ $urlTrim = preg_replace('/^\\s+/u', '', $urlDecode1) ?? $urlDecode1;
+ $parseScheme = preg_match('/^([\\w\\s]+):/u', strtolower($urlTrim), $matches);
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 's3'], true)) {
$cellData = htmlspecialchars($url, Settings::htmlEntityFlags());
} else {
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/BadCustomPropertyTest.php b/tests/PhpSpreadsheetTests/Writer/Html/BadCustomPropertyTest.php
new file mode 100644
index 0000000000..a9ef67b791
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Writer/Html/BadCustomPropertyTest.php
@@ -0,0 +1,23 @@
+load($infile);
+ $writer = new HtmlWriter($spreadsheet);
+ $html = $writer->generateHtmlAll();
+ self::assertStringContainsString('', $html);
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkBaseTest.php b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkBaseTest.php
new file mode 100644
index 0000000000..1f12bce570
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkBaseTest.php
@@ -0,0 +1,23 @@
+load($infile);
+ $writer = new HtmlWriter($spreadsheet);
+ $html = $writer->generateHtmlAll();
+ self::assertStringContainsString('', $html);
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php
new file mode 100644
index 0000000000..669594bb1c
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php
@@ -0,0 +1,23 @@
+load($infile);
+ $writer = new HtmlWriter($spreadsheet);
+ $html = $writer->generateHtmlAll();
+ self::assertStringContainsString("
jav\tascript:alert() | ", $html);
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/data/Reader/XLSX/sec-j47r.dontuse b/tests/data/Reader/XLSX/sec-j47r.dontuse
new file mode 100644
index 0000000000..9914b1ffd1
Binary files /dev/null and b/tests/data/Reader/XLSX/sec-j47r.dontuse differ
diff --git a/tests/data/Reader/XLSX/sec-p66w.dontuse b/tests/data/Reader/XLSX/sec-p66w.dontuse
new file mode 100644
index 0000000000..7257bfc9d3
Binary files /dev/null and b/tests/data/Reader/XLSX/sec-p66w.dontuse differ
diff --git a/tests/data/Reader/XLSX/sec-q229.dontuse b/tests/data/Reader/XLSX/sec-q229.dontuse
new file mode 100644
index 0000000000..edb9024987
Binary files /dev/null and b/tests/data/Reader/XLSX/sec-q229.dontuse differ