summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Roach <greg@subaqua.co.uk>2026-04-24 13:02:45 +0100
committerGreg Roach <greg@subaqua.co.uk>2026-04-24 13:02:45 +0100
commita8d95ceb87651e17ade08efee7a3b8b35001603b (patch)
tree773eeffd9ad8dc1194d65b77a1eabb4b2dd13e89
parentfc765b50f0f0a7129fb5fc904a764f1899ce5f73 (diff)
downloadwebtrees-a8d95ceb87651e17ade08efee7a3b8b35001603b.tar.gz
webtrees-a8d95ceb87651e17ade08efee7a3b8b35001603b.tar.bz2
webtrees-a8d95ceb87651e17ade08efee7a3b8b35001603b.zip
Add CSP to SVG error responses
-rw-r--r--app/Factories/ImageFactory.php10
-rw-r--r--tests/app/Factories/ImageFactoryTest.php13
2 files changed, 16 insertions, 7 deletions
diff --git a/app/Factories/ImageFactory.php b/app/Factories/ImageFactory.php
index 0e39d7993b..7141bb1497 100644
--- a/app/Factories/ImageFactory.php
+++ b/app/Factories/ImageFactory.php
@@ -260,9 +260,9 @@ class ImageFactory implements ImageFactoryInterface
$svg = view(name: 'errors/image-svg', data: ['status' => $text]);
// We can't send the actual status code, as browsers won't show images with 4xx/5xx.
- return response(content: $svg, code: StatusCodeInterface::STATUS_OK, headers: [
- 'content-type' => 'image/svg+xml',
- ]);
+ return response(content: $svg)
+ ->withHeader('content-type', 'image/svg+xml')
+ ->withHeader('content-security-policy', 'default-src none');
}
protected function imageResponse(string $data, string $mime_type, string $filename): ResponseInterface
@@ -272,10 +272,10 @@ class ImageFactory implements ImageFactoryInterface
->withHeader('x-image-exception', 'SVG image blocked due to XSS.');
}
- // HTML files may contain javascript and iframes, so use content-security-policy to disable them.
+ // HTML files may contain JavaScript and iframes, so use content-security-policy to disable them.
$response = response($data)
->withHeader('content-type', $mime_type)
- ->withHeader('content-security-policy', 'script-src none;frame-src none');
+ ->withHeader('content-security-policy', 'default-src none');
if ($filename === '') {
return $response;
diff --git a/tests/app/Factories/ImageFactoryTest.php b/tests/app/Factories/ImageFactoryTest.php
index b14f9ee8d3..3f77d78c1c 100644
--- a/tests/app/Factories/ImageFactoryTest.php
+++ b/tests/app/Factories/ImageFactoryTest.php
@@ -19,14 +19,23 @@ declare(strict_types=1);
namespace Fisharebest\Webtrees\Factories;
+use Fisharebest\Webtrees\Services\PhpService;
use Fisharebest\Webtrees\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
#[CoversClass(ImageFactory::class)]
class ImageFactoryTest extends TestCase
{
- public function testClass(): void
+ public function testReplacementImageResponseSetsContentSecurityPolicyHeader(): void
{
- self::assertTrue(class_exists(ImageFactory::class));
+ $php_service = $this->createStub(PhpService::class);
+ $image_factory = new ImageFactory($php_service);
+ $response = $image_factory->replacementImageResponse('404');
+
+ self::assertSame('image/svg+xml', $response->getHeaderLine('content-type'));
+ self::assertSame(
+ 'default-src none',
+ $response->getHeaderLine('content-security-policy'),
+ );
}
}