diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 67441f935c11..b0084cffed4a 100644 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -298,11 +298,11 @@ function video($src, string $unsupportedMessage = '', string $attributes = '', a $video = '\n"; @@ -400,7 +400,7 @@ function _media(string $name, array $types = [], string $unsupportedMessage = '' } if ($unsupportedMessage !== '') { - $media .= _space_indent() . $unsupportedMessage . "\n"; + $media .= _space_indent() . esc($unsupportedMessage, 'html') . "\n"; } return $media . ('\n"); @@ -425,8 +425,8 @@ function source(string $src, string $type = 'unknown', string $attributes = '', $src = $indexPage ? site_url($src) : slash_item('baseURL') . $src; } - $source = ''; } } @@ -478,7 +478,7 @@ function object(string $data, string $type = 'unknown', string $attributes = '', $data = $indexPage ? site_url($data) : slash_item('baseURL') . $data; } - $object = ''; if ($params !== []) { @@ -507,9 +507,9 @@ function object(string $data, string $type = 'unknown', string $attributes = '', */ function param(string $name, string $value, string $type = 'ref', string $attributes = ''): string { - return ''; } } @@ -531,8 +531,8 @@ function embed(string $src, string $type = 'unknown', string $attributes = '', b $src = $indexPage ? site_url($src) : slash_item('baseURL') . $src; } - return '\n"; } } @@ -556,3 +556,13 @@ function _space_indent(int $depth = 2): string return str_repeat(' ', $depth); } } + +if (! function_exists('_esc_attr')) { + /** + * Escapes a value for use inside a double-quoted HTML attribute. + */ + function _esc_attr(string $value): string + { + return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); + } +} diff --git a/tests/system/Helpers/HTMLHelperTest.php b/tests/system/Helpers/HTMLHelperTest.php index 787b100bbf2b..d54b17848b73 100644 --- a/tests/system/Helpers/HTMLHelperTest.php +++ b/tests/system/Helpers/HTMLHelperTest.php @@ -890,4 +890,141 @@ public function testObjectIndexed(): void $this->assertSame($expected, $object); } + + public function testVideoEscaping(): void + { + $src = 'http://example.com/test.mp4" onerror="alert(1)'; + $message = ''; + + $html = video($src, $message, 'controls'); + + $this->assertStringNotContainsString('onerror="alert(1)', $html); + $this->assertStringNotContainsString(''); + $this->assertStringNotContainsString(''; + + $html = audio($src, $message, 'controls'); + + $this->assertStringNotContainsString('onerror="alert(1)', $html); + $this->assertStringNotContainsString(''; + + $html = _media('video', $sources, $message); + + $this->assertStringNotContainsString('