Attachments: Aligned ZipExportAttachment link validation

With controller routes.
Don't consider this as a security issue, since the filtered URLs
by that validation are very likely to be blocked by browser security
or CSP, and there's a level of assumed privilege to the users that
are able to create such attachments links already.

Closes #6093
This commit is contained in:
Dan Brown
2026-04-12 15:17:31 +01:00
parent 4e3fa4822f
commit c7e2b487c1
2 changed files with 26 additions and 1 deletions

View File

@@ -45,7 +45,7 @@ final class ZipExportAttachment extends ZipExportModel
$rules = [
'id' => ['nullable', 'int', $context->uniqueIdRule('attachment')],
'name' => ['required', 'string', 'min:1'],
'link' => ['required_without:file', 'nullable', 'string'],
'link' => ['required_without:file', 'nullable', 'string', 'safe_url'],
'file' => ['required_without:link', 'nullable', 'string', $context->fileReferenceRule()],
];

View File

@@ -90,4 +90,29 @@ class ZipExportValidatorTest extends TestCase
$this->assertEquals('The file needs to reference a file of type image/png,image/jpeg,image/gif,image/webp, found text/plain.', $results['page.images.0.file']);
}
public function test_page_link_attachments_cant_be_data_or_js()
{
$validateResultCountByLink = [
'data:text/html,<p>hi</p>' => 1,
'javascript:alert(\'hi\')' => 1,
'mailto:email@example.com' => 0,
];
foreach ($validateResultCountByLink as $link => $count) {
$validator = $this->getValidatorForData([
'page' => [
'id' => 4,
'name' => 'My page',
'markdown' => 'hello',
'attachments' => [
['id' => 4, 'name' => 'Attachment A', 'link' => $link],
],
]
]);
$results = $validator->validate();
$this->assertCount($count, $results);
}
}
}