From 37f2d05118fa98ee9cb68b8a51c6ae90612de813 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 6 Jun 2026 10:37:06 +0100 Subject: [PATCH 1/5] Search: Prevented tag search using unusable numbers These would trigger an error on use, and could be abused to fill logs. Added test to cover. Thanks to Stephen O. / Sakusen for reporting. --- app/Search/SearchRunner.php | 2 +- tests/Search/EntitySearchTest.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/Search/SearchRunner.php b/app/Search/SearchRunner.php index 391254172..d49cb439a 100644 --- a/app/Search/SearchRunner.php +++ b/app/Search/SearchRunner.php @@ -290,7 +290,7 @@ class SearchRunner $query->where('name', '=', $tagParts['name']); } - if (is_numeric($tagParts['value']) && $tagParts['operator'] !== 'like') { + if (is_numeric($tagParts['value']) && is_finite($tagParts['value']) && $tagParts['operator'] !== 'like') { // We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will // search the value as a string which prevents being able to do number-based operations // on the tag values. We ensure it has a numeric value and then cast it just to be sure. diff --git a/tests/Search/EntitySearchTest.php b/tests/Search/EntitySearchTest.php index fc300241b..d29c44eda 100644 --- a/tests/Search/EntitySearchTest.php +++ b/tests/Search/EntitySearchTest.php @@ -233,6 +233,18 @@ class EntitySearchTest extends TestCase $this->get('/search?term=' . urlencode('danzorbhsing {created_before:2037-01-01}'))->assertDontSee($page->name); } + public function test_search_tags_with_unexpected_numeric_values_does_not_cause_error() + { + $pageA = $this->entities->page(); + $pageA->name = 'MyTestPageWithAwkwardNumericTagValue'; + $pageA->save(); + $pageA->tags()->save(new Tag(['name' => 'Count', 'value' => '1E999'])); + + $resp = $this->asEditor()->get('/search?term=' . urlencode('[Count=1E999]')); + $resp->assertStatus(200); + $resp->assertSee('MyTestPageWithAwkwardNumericTagValue'); + } + public function test_entity_selector_search() { $page = $this->entities->newPage(['name' => 'my ajax search test', 'html' => 'ajax test']); From 81f77a95de4b060fa77a5376198a80a24cfcca59 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 6 Jun 2026 15:21:15 +0100 Subject: [PATCH 2/5] Content Filtering: Limited file protocol to just anchor hrefs Updated allow list/purifier system to only allow file protocol use on anchor hrefs to avoid potential security concerns with, after export, content being auto loaded via interactive elements like embeds/objects/videos etc... Updated tests to cover. Thanks to Gurmandeep Deol at Seneca Polytechnic for reporting. --- app/Util/HtmlContentFilter.php | 1 + .../ConfiguredHtmlPurifier.php | 19 ++++++- .../Filters/UriLimitFileProtocolToAnchors.php | 55 +++++++++++++++++++ tests/Entity/PageContentFilteringTest.php | 7 +++ 4 files changed, 79 insertions(+), 3 deletions(-) rename app/Util/{ => HtmlPurifier}/ConfiguredHtmlPurifier.php (86%) create mode 100644 app/Util/HtmlPurifier/Filters/UriLimitFileProtocolToAnchors.php diff --git a/app/Util/HtmlContentFilter.php b/app/Util/HtmlContentFilter.php index 2ef797d13..26f22e6ca 100644 --- a/app/Util/HtmlContentFilter.php +++ b/app/Util/HtmlContentFilter.php @@ -2,6 +2,7 @@ namespace BookStack\Util; +use BookStack\Util\HtmlPurifier\ConfiguredHtmlPurifier; use DOMAttr; use DOMElement; use DOMNodeList; diff --git a/app/Util/ConfiguredHtmlPurifier.php b/app/Util/HtmlPurifier/ConfiguredHtmlPurifier.php similarity index 86% rename from app/Util/ConfiguredHtmlPurifier.php rename to app/Util/HtmlPurifier/ConfiguredHtmlPurifier.php index 1f2528e71..307cdb74f 100644 --- a/app/Util/ConfiguredHtmlPurifier.php +++ b/app/Util/HtmlPurifier/ConfiguredHtmlPurifier.php @@ -1,13 +1,15 @@ getDefinition('HTML', true, true); if ($htmlDef instanceof HTMLPurifier_HTMLDefinition) { - $this->configureDefinition($htmlDef); + $this->configureHtmlDefinition($htmlDef); + } + + /** @var \HTMLPurifier_URIDefinition $uriDef */ + $uriDef = $config->getDefinition('URI', true, true); + if ($uriDef instanceof HTMLPurifier_URIDefinition) { + $this->configureUriDefinition($uriDef); } $this->purifier = new HTMLPurifier($config); @@ -91,7 +99,7 @@ class ConfiguredHtmlPurifier // $config->set('Cache.DefinitionImpl', null); // Disable cache during testing } - public function configureDefinition(HTMLPurifier_HTMLDefinition $definition): void + protected function configureHtmlDefinition(HTMLPurifier_HTMLDefinition $definition): void { // Allow the object element $definition->addElement( @@ -151,6 +159,11 @@ class ConfiguredHtmlPurifier $definition->addAttribute('a', 'data-mention-user-id', 'Number'); } + protected function configureUriDefinition(HTMLPurifier_URIDefinition $definition): void + { + $definition->registerFilter(new UriLimitFileProtocolToAnchors()); + } + public function purify(string $html): string { return $this->purifier->purify($html); diff --git a/app/Util/HtmlPurifier/Filters/UriLimitFileProtocolToAnchors.php b/app/Util/HtmlPurifier/Filters/UriLimitFileProtocolToAnchors.php new file mode 100644 index 000000000..19ca9cc82 --- /dev/null +++ b/app/Util/HtmlPurifier/Filters/UriLimitFileProtocolToAnchors.php @@ -0,0 +1,55 @@ +scheme !== 'file') { + return true; + } + + $token = $context->get('CurrentToken', true); + $attr = $context->get('CurrentAttr', true); + + // Only allow if used on hrefs on anchor tags + $isAnchor = $token && $token->name === 'a'; + $isHref = $attr === 'href'; + if ($isAnchor && $isHref) { + return true; + } + + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/tests/Entity/PageContentFilteringTest.php b/tests/Entity/PageContentFilteringTest.php index 449189a89..0ebbd9a0e 100644 --- a/tests/Entity/PageContentFilteringTest.php +++ b/tests/Entity/PageContentFilteringTest.php @@ -464,6 +464,11 @@ HTML; '
Hello!
' => '
Hello!
', '
Hello!
' => '
Hello!
', '
Hello!
' => '
Hello!
', + '' => '', + '' => '', + '' => '', + '
My local image
' => '
', + '
My local image
' => '
', ]; config()->set('app.content_filtering', 'a'); @@ -476,6 +481,7 @@ HTML; $resp = $this->get($page->getUrl()); $resp->assertSee($expected, false); + $resp->assertDontSee($input, false); } } @@ -484,6 +490,7 @@ HTML; $testCasesExpectedByInput = [ '

New tab linkydoodle

', '

@mentionusertext

', + '

Link to file

', '
Hello

Mydetailshere

', ]; From b7325fdf0efde6f863beed67cde488641a05ef83 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 7 Jun 2026 10:22:52 +0100 Subject: [PATCH 3/5] Attachments: Moved perm checks before validation Avoids providing responses with potential sensitive attachment info before permission checks. Added tests to cover. Thanks to Rafael Castilho for reporting. --- .../Controllers/AttachmentController.php | 16 ++++------ tests/Uploads/AttachmentTest.php | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/app/Uploads/Controllers/AttachmentController.php b/app/Uploads/Controllers/AttachmentController.php index 12f49dffe..bdd96d6ad 100644 --- a/app/Uploads/Controllers/AttachmentController.php +++ b/app/Uploads/Controllers/AttachmentController.php @@ -107,6 +107,9 @@ class AttachmentController extends Controller { /** @var Attachment $attachment */ $attachment = Attachment::query()->findOrFail($attachmentId); + $this->checkOwnablePermission(Permission::PageView, $attachment->page); + $this->checkOwnablePermission(Permission::PageUpdate, $attachment->page); + $this->checkOwnablePermission(Permission::AttachmentUpdate, $attachment); try { $this->validate($request, [ @@ -120,10 +123,6 @@ class AttachmentController extends Controller ]), 422); } - $this->checkOwnablePermission(Permission::PageView, $attachment->page); - $this->checkOwnablePermission(Permission::PageUpdate, $attachment->page); - $this->checkOwnablePermission(Permission::AttachmentUpdate, $attachment); - $attachment = $this->attachmentService->updateFile($attachment, [ 'name' => $request->input('attachment_edit_name'), 'link' => $request->input('attachment_edit_url'), @@ -142,6 +141,10 @@ class AttachmentController extends Controller public function attachLink(Request $request) { $pageId = $request->input('attachment_link_uploaded_to'); + $page = $this->pageQueries->findVisibleByIdOrFail($pageId); + + $this->checkPermission(Permission::AttachmentCreateAll); + $this->checkOwnablePermission(Permission::PageUpdate, $page); try { $this->validate($request, [ @@ -156,11 +159,6 @@ class AttachmentController extends Controller ]), 422); } - $page = $this->pageQueries->findVisibleByIdOrFail($pageId); - - $this->checkPermission(Permission::AttachmentCreateAll); - $this->checkOwnablePermission(Permission::PageUpdate, $page); - $attachmentName = $request->input('attachment_link_name'); $link = $request->input('attachment_link_url'); $this->attachmentService->saveNewFromLink($attachmentName, $link, intval($pageId)); diff --git a/tests/Uploads/AttachmentTest.php b/tests/Uploads/AttachmentTest.php index 2d402c340..22e4f4610 100644 --- a/tests/Uploads/AttachmentTest.php +++ b/tests/Uploads/AttachmentTest.php @@ -159,6 +159,38 @@ class AttachmentTest extends TestCase $this->files->deleteAllAttachmentFiles(); } + public function test_attachment_update_without_permission() + { + $page = $this->entities->page(); + $attachment = Attachment::factory()->create(['uploaded_to' => $page->id]); + + $this->permissions->disableEntityInheritedPermissions($page); + + $resp = $this->asViewer()->put("attachments/{$attachment->id}", [ + 'attachment_edit_name' => 'My new attachment name', + 'attachment_edit_url' => 'https://test.example.com', + ]); + + $this->assertPermissionError($resp); + } + + public function test_attachment_update_without_permission_with_validation_errors() + { + $page = $this->entities->page(); + /** @var Attachment $attachment */ + $attachment = Attachment::factory()->create(['uploaded_to' => $page->id]); + + $this->permissions->disableEntityInheritedPermissions($page); + + $resp = $this->asViewer()->put("attachments/{$attachment->id}", [ + 'attachment_edit_name' => '', + 'attachment_edit_url' => 'https://test.example.com', + ]); + + $this->assertPermissionError($resp); + $resp->assertDontSee($attachment->path); + } + public function test_file_deletion() { $page = $this->entities->page(); From 84a23fb23f8d15935521ad4f3fdc335be6d90744 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 7 Jun 2026 10:45:40 +0100 Subject: [PATCH 4/5] Logs: Prevented NotifyExceptions for reporting to error logs This is to reduce the amount of content which will be logged, since these messages don't really indicate an actual system error but advise the user of something which went wrong with their request. --- app/Exceptions/Handler.php | 1 + app/Exceptions/NotifyException.php | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 08d326ad8..97a2b0a4f 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -25,6 +25,7 @@ class Handler extends ExceptionHandler protected $dontReport = [ NotFoundException::class, StoppedAuthenticationException::class, + NotifyException::class, ]; /** diff --git a/app/Exceptions/NotifyException.php b/app/Exceptions/NotifyException.php index b62b8fde6..d2fba30c4 100644 --- a/app/Exceptions/NotifyException.php +++ b/app/Exceptions/NotifyException.php @@ -6,18 +6,22 @@ use Exception; use Illuminate\Contracts\Support\Responsable; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; +/** + * An exception that is thrown to notify the user of something which went wrong. + * Typically these should be translated messages since they will be shown to the end user + * via a pop up notification error message in the UI. + * + * This exception is not intended to be used for internal system/application errors, + * and therefore will not be logged by the exception handler. + */ class NotifyException extends Exception implements Responsable, HttpExceptionInterface { - public $message; - public string $redirectLocation; - protected int $status; - - public function __construct(string $message, string $redirectLocation = '/', int $status = 500) - { + public function __construct( + string $message, + public string $redirectLocation = '/', + protected int $status = 500 + ) { $this->message = $message; - $this->redirectLocation = $redirectLocation; - $this->status = $status; - parent::__construct(); } From cc0b059fa496e265839733ed30a1ba121274dfab Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 9 Jun 2026 12:47:28 +0100 Subject: [PATCH 5/5] Deps: Updated PHP package versions --- composer.lock | 118 ++++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/composer.lock b/composer.lock index 710067eb0..e07268399 100644 --- a/composer.lock +++ b/composer.lock @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.382.2", + "version": "3.384.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "6844cc6421c47d6b96633ab8039045012acbeb27" + "reference": "c7d34f2d60515bd0c307e462268f75877842da4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6844cc6421c47d6b96633ab8039045012acbeb27", - "reference": "6844cc6421c47d6b96633ab8039045012acbeb27", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c7d34f2d60515bd0c307e462268f75877842da4a", + "reference": "c7d34f2d60515bd0c307e462268f75877842da4a", "shasum": "" }, "require": { @@ -153,9 +153,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.382.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.384.5" }, - "time": "2026-05-27T18:11:41+00:00" + "time": "2026-06-08T18:25:02+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1179,25 +1179,26 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.10.5", + "version": "7.11.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7c8d84b39e680315f687e8662a9d6fb0865c5148" + "reference": "5af96f374e0ab4ebd747b8310888c99d3adb0a8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7c8d84b39e680315f687e8662a9d6fb0865c5148", - "reference": "7c8d84b39e680315f687e8662a9d6fb0865c5148", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/5af96f374e0ab4ebd747b8310888c99d3adb0a8c", + "reference": "5af96f374e0ab4ebd747b8310888c99d3adb0a8c", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^2.3", - "guzzlehttp/psr7": "^2.8", + "guzzlehttp/promises": "^2.5", + "guzzlehttp/psr7": "^2.11", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.24" }, "provide": { "psr/http-client-implementation": "1.0" @@ -1206,7 +1207,7 @@ "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "guzzle/client-integration-tests": "3.0.2", - "guzzlehttp/test-server": "^0.4", + "guzzlehttp/test-server": "^0.5", "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.52 || ^9.6.34", "psr/log": "^1.1 || ^2.0 || ^3.0" @@ -1286,7 +1287,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.10.5" + "source": "https://github.com/guzzle/guzzle/tree/7.11.1" }, "funding": [ { @@ -1302,24 +1303,25 @@ "type": "tidelift" } ], - "time": "2026-05-27T11:53:46+00:00" + "time": "2026-06-07T22:54:06+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.4.1", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "09e8a212562fb1fb6a512c4156ed71525969d6c2" + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/09e8a212562fb1fb6a512c4156ed71525969d6c2", - "reference": "09e8a212562fb1fb6a512c4156ed71525969d6c2", + "url": "https://api.github.com/repos/guzzle/promises/zipball/4360e982f87f5f258bf872d094647791db2f4c8e", + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" + "php": "^7.2.5 || ^8.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -1369,7 +1371,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.4.1" + "source": "https://github.com/guzzle/promises/tree/2.5.0" }, "funding": [ { @@ -1385,27 +1387,29 @@ "type": "tidelift" } ], - "time": "2026-05-20T22:57:30+00:00" + "time": "2026-06-02T12:23:43+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.10.3", + "version": "2.11.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "7c1472269227dc6f18930bd903d7a88fe6c52130" + "reference": "bbb5e61349fa5cb822b3e87842b951088b76b81f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/7c1472269227dc6f18930bd903d7a88fe6c52130", - "reference": "7c1472269227dc6f18930bd903d7a88fe6c52130", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/bbb5e61349fa5cb822b3e87842b951088b76b81f", + "reference": "bbb5e61349fa5cb822b3e87842b951088b76b81f", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" + "ralouphie/getallheaders": "^3.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.24" }, "provide": { "psr/http-factory-implementation": "1.0", @@ -1486,7 +1490,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.10.3" + "source": "https://github.com/guzzle/psr7/tree/2.11.0" }, "funding": [ { @@ -1502,7 +1506,7 @@ "type": "tidelift" } ], - "time": "2026-05-27T11:48:20+00:00" + "time": "2026-06-02T12:30:48+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1803,16 +1807,16 @@ }, { "name": "laravel/framework", - "version": "v12.61.0", + "version": "v12.61.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1124062a1ca92d290c8bcb9b7f649920fa6816bf" + "reference": "e8472ca9774452fe50841d9bdced060679f4d58d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1124062a1ca92d290c8bcb9b7f649920fa6816bf", - "reference": "1124062a1ca92d290c8bcb9b7f649920fa6816bf", + "url": "https://api.github.com/repos/laravel/framework/zipball/e8472ca9774452fe50841d9bdced060679f4d58d", + "reference": "e8472ca9774452fe50841d9bdced060679f4d58d", "shasum": "" }, "require": { @@ -2021,7 +2025,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-05-26T23:41:33+00:00" + "time": "2026-06-04T14:22:52+00:00" }, { "name": "laravel/prompts", @@ -4191,16 +4195,16 @@ }, { "name": "predis/predis", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/predis/predis.git", - "reference": "2033429520d8997a7815a2485f56abe6d2d0e075" + "reference": "8cc4319c06924c8ff0c5c7eec4243a19e3be32f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/predis/predis/zipball/2033429520d8997a7815a2485f56abe6d2d0e075", - "reference": "2033429520d8997a7815a2485f56abe6d2d0e075", + "url": "https://api.github.com/repos/predis/predis/zipball/8cc4319c06924c8ff0c5c7eec4243a19e3be32f1", + "reference": "8cc4319c06924c8ff0c5c7eec4243a19e3be32f1", "shasum": "" }, "require": { @@ -4242,7 +4246,7 @@ ], "support": { "issues": "https://github.com/predis/predis/issues", - "source": "https://github.com/predis/predis/tree/v3.4.2" + "source": "https://github.com/predis/predis/tree/v3.5.0" }, "funding": [ { @@ -4250,7 +4254,7 @@ "type": "github" } ], - "time": "2026-03-09T20:33:04+00:00" + "time": "2026-06-02T19:25:56+00:00" }, { "name": "psr/clock", @@ -6845,16 +6849,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.38.1", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92", - "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -6906,7 +6910,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -6926,7 +6930,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T12:51:13+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/polyfill-php80", @@ -7014,16 +7018,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.38.1", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "8339098cae28673c15cce00d80734af0453054e2" + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/8339098cae28673c15cce00d80734af0453054e2", - "reference": "8339098cae28673c15cce00d80734af0453054e2", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8", "shasum": "" }, "require": { @@ -7070,7 +7074,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.2" }, "funding": [ { @@ -7090,7 +7094,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T12:51:13+00:00" + "time": "2026-05-27T06:51:48+00:00" }, { "name": "symfony/polyfill-php84", @@ -9179,11 +9183,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.0", + "version": "2.2.2", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4cd98348c809924f62bb9cc8c047f5e73bc9a58", - "reference": "b4cd98348c809924f62bb9cc8c047f5e73bc9a58", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", "shasum": "" }, "require": { @@ -9239,7 +9243,7 @@ "type": "github" } ], - "time": "2026-05-28T08:22:43+00:00" + "time": "2026-06-05T09:00:01+00:00" }, { "name": "phpunit/php-code-coverage",