Skip to content

Commit

Permalink
Backport Html Writer Security Patches
Browse files Browse the repository at this point in the history
  • Loading branch information
oleibman committed Dec 27, 2024
1 parent a50ebfe commit 02c8625
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 5 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com)
and this project adheres to [Semantic Versioning](https://semver.org).

# TBD - 1.29.7
# 2024-12-26 - 1.29.7

### Deprecated

Expand All @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).

- More context options may be needed for http(s) image. Backport of [PR #4276](https://github.com/PHPOffice/PhpSpreadsheet/pull/4276)
- Backported security patches for Samples.
- Backported security patches for Html Writer.

## 1.29.6 - 2024-12-08

Expand Down
9 changes: 5 additions & 4 deletions src/PhpSpreadsheet/Writer/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,12 @@ public function generateHTMLHeader($includeStyles = false)
} else {
$propertyValue = (string) $propertyValue;
}
$html .= self::generateMeta($propertyValue, "custom.$propertyQualifier.$customProperty");
$html .= self::generateMeta($propertyValue, htmlspecialchars("custom.$propertyQualifier.$customProperty"));
}
}

if (!empty($properties->getHyperlinkBase())) {
$html .= ' <base href="' . $properties->getHyperlinkBase() . '" />' . PHP_EOL;
$html .= ' <base href="' . htmlspecialchars($properties->getHyperlinkBase()) . '" />' . PHP_EOL;
}

$html .= $includeStyles ? $this->generateStyles(true) : $this->generatePageDeclarations(true);
Expand Down Expand Up @@ -1519,8 +1519,9 @@ private function generateRow(Worksheet $worksheet, array $values, $row, $cellTyp
// Hyperlink?
if ($worksheet->hyperlinkExists($coordinate) && !$worksheet->getHyperlink($coordinate)->isInternal()) {
$url = $worksheet->getHyperlink($coordinate)->getUrl();
$urldecode = strtolower(html_entity_decode(trim($url), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, '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 {
Expand Down
23 changes: 23 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Html/BadCustomPropertyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;

class BadCustomPropertyTest extends TestCase
{
public function testBadCustomProperty(): void
{
$reader = new XlsxReader();
$infile = 'tests/data/Reader/XLSX/sec-q229.dontuse';
$spreadsheet = $reader->load($infile);
$writer = new HtmlWriter($spreadsheet);
$html = $writer->generateHtmlAll();
self::assertStringContainsString('<meta name="custom.string.custom_property&quot;&gt;&lt;img src=1 onerror=alert()&gt;" content="test" />', $html);
$spreadsheet->disconnectWorksheets();
}
}
23 changes: 23 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkBaseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;

class BadHyperlinkBaseTest extends TestCase
{
public function testBadHyperlinkBase(): void
{
$reader = new XlsxReader();
$infile = 'tests/data/Reader/XLSX/sec-p66w.dontuse';
$spreadsheet = $reader->load($infile);
$writer = new HtmlWriter($spreadsheet);
$html = $writer->generateHtmlAll();
self::assertStringContainsString('<base href="&quot;&gt;&lt;img src=1 onerror=alert()&gt;" />', $html);
$spreadsheet->disconnectWorksheets();
}
}
23 changes: 23 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Html/BadHyperlinkTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;

class BadHyperlinkTest extends TestCase
{
public function testBadHyperlink(): void
{
$reader = new XlsxReader();
$infile = 'tests/data/Reader/XLSX/sec-j47r.dontuse';
$spreadsheet = $reader->load($infile);
$writer = new HtmlWriter($spreadsheet);
$html = $writer->generateHtmlAll();
self::assertStringContainsString("<td class=\"column0 style1 f\">jav\tascript:alert()</td>", $html);
$spreadsheet->disconnectWorksheets();
}
}
Binary file added tests/data/Reader/XLSX/sec-j47r.dontuse
Binary file not shown.
Binary file added tests/data/Reader/XLSX/sec-p66w.dontuse
Binary file not shown.
Binary file added tests/data/Reader/XLSX/sec-q229.dontuse
Binary file not shown.

0 comments on commit 02c8625

Please sign in to comment.