NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #5311 most downloaded on Packagist
The Kirby core
Last release 2 days ago
06 Oct 2026
Ships fairly regularly
a new release about every 3 weeks
Rarely documented
notes for 13 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
291 releases · first in 2019
All our security fixes and improvements from our Kirby 5 security releases
Kirby 6.0.0-alpha.3 is an early developer preview. We plan for a final release in the second half of 2026. Kirby 6 will be a free upgrade for all Kirby 4 & 5 license holders.
Important
Don't use Kirby 6 in production yet
All our security fixes and improvements from our Kirby 5 security releases
A single place on the user/account view to handle security-related matters, e.g. email, password, two-factor (TOTP) management
The login view has been refactored from the ground up to be more driven by the backend. It now features a method picker, a challenge switcher, and centralized loading/error handling. Auth methods can now also authenticate without an email, enabling token/SSO-style plugin methods that don't key on email and plugins can ship their own login method, just like custom challenges. Passkey is coming …
The new auth.passwords option allows you to define a custom password policy for all users.
// site/config/config.php
return [
'auth' => [
'passwords' => [
'minlength' => 12,
'uppercase' => true,
'lowercase' => true,
'digits' => 2,
'symbols' => true
]
]
];We are collecting all changes in our pre-release changelog, if you already want to dive deeper: https://github.com/getkirby/kirby/blob/6.0.0-alpha.3/CHANGELOG.md
One column per quarter.
Nothing published for this version
Nothing published for this version
Cropping thumbnails uses less memory #8497
create blueprint option #8527_globals, _json, _only, _pretty) no longer show up in the Panel URL #85080 #85180 no longer fall back to another language #8523image.ratio option (e.g. in pages/files section) now works with Kirby queries https://forum.getkirby.com/t/custom-cropratio-and-cover-true-for-the-image-settings-in-a-section-generates-an-error/35615/4create: blueprint option no longer converts uploaded files to the global thumbs.format #8489Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
Dom::sanitize() - CVSS Score 7.4files, pages and users fields resolve their stored value - CVSS Score 7.1root and dirname parameters - CVSS Score 7.1Thanks to the following reporters for responsibly reporting the identified issues
root and dirname on page creation@import string form in Dom::extractUrls()k-link no longer accept dangerous URL schemes (javascript: etc.).languages.update permission could inject HTML markup into other users' Panels. To override a core string, use the translations extension in your config as before.– and keep their stored value.(date:) KirbyTag keeps cached pages up to date and supports a new optional expiry attribute #7746(date: year) // cache resets at the start of next year
(date: Y-m-d) // no expiry unless set
(date: Y-m-d expiry: tomorrow) // cache resets at midnightX-Robots-Tag: noindex, nofollowheader and the Panel document includes a matching robots meta tag. #8446Kirby\Template\Template::sanitizeName() methodUrl::normalize() method that brings a URL into the same form a browser parses.<a> tags anymore #5481k-textarea-input: (pre)-selecting works again$helper.string.unescapeHTML() does not unescape entities twice anymore #8345object or toggle #8355Page::create(), File::create() and User::create() use the fields' save handlers again, just like ::update()does. This restores the v4 behavior. Values a field can't handle are normalized or dropped. #8440Page::create(), File::create() and User::create() are checked before the given content is processed, so unauthorized requests are rejected upfront. #8440Sql::joins() returns the bindings collected from its joins instead of discarding them. #8460Sql::insert() no longer fails with a TypeError when called without explicit bindings. #8461Database::connect() throws a clear InvalidArgumentException for incomplete connection options instead of a TypeError. #8463Database::connect() no longer leaves the object with a partially updated configuration; the previous connection stays intact. #8463Sql::unquoteIdentifier() no longer unwraps identifiers whose opening and closing quotes don't match, and no longer mangles the other quote character inside a quoted identifier. #8462$page->changeTemplate() and $file->changeTemplate() no longer delete the existing content before the converted content has been written. If writing fails, the old content stays intact. #8473+ as %2B #8485Kirby\Toolkit\Html::youtube() domains. (thx to @bnomei and Danish Tariq of Laburity for their suggestion and responsible disclosure).kirby.resetPassword session flag now gets cleared on logouta.jpg to b with new extension png no longer overlooks an existing b.png.Kirby\Cms\Inventory class used for page, site and user content dir inventories #8137Uuid classes carry generic type templates, so PageUuid::model(), FileUuid::model() etc. are statically typed as the specific model #8368Database::connect() now takes array $params = [] instead of array|null $params = null, matching the constructor. Passing null was never supported. #8463Kirby\Filesystem\Dir::inventory is deprecated. Use Kirby\Cms\Inventory::for instead. #8137$model->createDefaultContent() has been deprecated, use $model->createContent() instead. #8440Kirby\Sane\Html::options() & Kirby\Sane\Svg::options() are now publicThe Panel is no longer blocked by a deprecation warning when a user blueprint sets an undefined permission #8319
slugs config option in the Panel #8300filename is provided to File::create() #8316Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
This vulnerability affects all Kirby sites that are deployed to a server that allows to request URLs with encoded slashes (%2f) such as nginx, the built-in PHP server or Apache setups that have the option AllowEncodedSlashes enabled.
It was possible to create and access thumbnails from media files in arbitrary accessible directories on the server that have a valid thumbnail configuration (JSON job file). It was also possible to detect the presence of files with the .json file extension anywhere on the server.
This vulnerability is of high severity for affected sites.
Server setups running on Apache's default configuration or other servers that have been hardened against encoded slashes in URLs are not affected.
Thanks to Jorge González Milla (@Pig-Tail) for responsibly reporting the identified issue.
This vulnerability affects all Kirby sites where users of a particular role have access to the REST API (access.panel permission is enabled) but no permission to upload any kind of file (files.create, files.replace and user/users.update permissions are all disabled).
It was possible to fill up the temporary directory for chunked uploads with unfinished chunks even as a user without any upload permission.
This vulnerability is of high severity for affected sites.
Your Kirby sites are not affected if you intend all users of your site to be able to upload files. The vulnerability can only be exploited by authenticated users. It was not possible to bypass the actual permission checks for any files that end up in the content or site/accounts folders.
Thanks to @alcls01111 for responsibly reporting the identified issue.
This vulnerability affects all Kirby sites that have not disabled the REST API with the 'api' => false option.
It was possible to trigger a PHP error in the API backend that would expose the full filesystem path of the Kirby installation on the server. This could be used to guess the default content.salt or prepare specialized attacks.
Thanks to Peter Levashov (@petersevera) for responsibly reporting the identified issue.
This vulnerability affects all Kirby sites that are deployed in a way that their index root on the server is next to a second directory that is read-accessible to PHP and shares the same name prefix (such as the site with the index root /var/www/site being next to /var/www/site2).
It was possible to create and access thumbnails from media files within such sibling directories that have a valid thumbnail configuration (JSON job file). This can affect staging sites, site backups or other internal sites.
Thanks to @0x1saac for responsibly reporting the identified issue.
Kirby\Filesystem\Dir::realpath()/Kirby\Filesystem\F::realpath(): Fixed path traversal via prefix match. Now requires an exact match or a DIRECTORY_SEPARATOR boundary.Kirby\Cms\Media::thumb(): Rejects path traversals via filenamesAsset class and asset() helper no longer accept paths with ../ sequences to protect against path traversalsite/cache/.uploads.maxsize consistently across all chunks and reject requests that change the file template or total upload length between chunks.site.preview permission as well as pages.preview permission/option for the home pageModelPermissions::canFromCache() handling of $default argument, incl. proper caching of itsite.preview. The check for the home page pages.preview permission has been deprecated and will be removed in the next major release. Please use the site.preview permission.Added deprecation id for permission deprecate warnings #8253
A (link:) tag with an unresolvable UUID (e.g. deleted page/file) threw an NotFoundException in the previous release, which turned the whole page into the error page. Instead of that drastic exception (added in #6085), we now handle the broken link inline: in debug mode a visible inline error (prefixed with an emoji and a kirby-broken-link class so it can be targeted via CSS, and in production the link is simply dropped (keeping its text). #7426
(link: page://deleted-page)
→ <span class="kirby-broken-link">🚨 The link "page://deleted-page" cannot be found</span>
(link: page://deleted-page text: click here)
→ <span class="kirby-broken-link">🚨 The link "page://deleted-page" cannot be found for the link text "click here"</span>
(link: file://deleted-file text: file) → <span>file</span>
(link: page://deleted-page) → (nothing)
type: html Panel field preview rendering #8242(link:) tag no longer turns the whole page into the error page #8257…Block error message. While this is technically a breaking change, we see this as a debugging enhancement which can clearly go into a minor release wit…
A Kirby site can now be activated as development site when you confirm to comply with the license terms for free development licenses. When the site is not set up locally, Kirby will regularly check that your development site is not publicly accessible. #7832
New Frontmatter Data handler, which can be used to import or export frontmatter into Kirby. #8019
Decoding
use Kirby\Data\Frontmatter;
$md = <<<MD
---
title: My new article
date: '2026-03-12'
---
# Hello world
This is my brand new article written in **Frontmatter/Markdown**
MD;
$result = Frontmatter::decode($md);
// [
// 'title' => 'My new article',
// 'date' => '2026-03-12',
// 'text' => '# Hello world ...'
// ]Encoding
use Kirby\Data\Frontmatter;
$result = Frontmatter::encode([
'title' => 'My new article',
'date' => '2026-03-12',
'text' => '# Hello world …'
]);
// ---
// title: My new article
// date: 2026-03-12
// ---
// # Hello world …Kirby\Content\Version::unlock() methodpanel.content.unlock() method/api/(:all)/changes/unlock routethis.$helper.string.sanitizeHTML() in the Panel to create a clean HTML string with configurable marks and nodes. By default, the sanitizer will only keep inline marks (bold, code, italic, link, strike, sub, sup, underline) #7922
this.$helper.string.sanitizeHTML('<p><marquee><strong onclick="alert(\'boo\')">Foo</strong></marquee></p>')
// returns: <strong>Foo</strong>this.$helper.string.sanitizeHTML(unsanitizedHTML, {
marks: ["bold"],
nodes: ["doc", "praagraph", "text")]
});// /site/config/config.php
return [
'extensions' => [
'pageModels' => [
// ...
],
'blueprints' => [
// ...
]
]
];Kirby\Filesystem\F::$types and Kirby\Filesystem\Mime::$types. #8134Kirby\Toolkit\A::flip() method #8132Kirby\Filesystem\F::update($file, $callback) method that reads and updates a file under lock #8187Kirby\Cms\Block::toHtml() by logging suppressed errors and escalating exceptions in debug mode #8085.Kirby\Filesystem\Dir::size() #8131Kirby\Filesystem\Mime::fromSvg() #8130Kirby\Filesystem\Mime::toExtension() and Kirby\Filesystem\Mime::toExtensions() #8133Kirby\Toolkit\Controller #8143Kirby\Toolkit\Html::attr() and Kirby|Toolkit\Xml::encode() #8144Kirby\Toolkit\Str::similarity(), Kirby\Toolkit\Str::startsWith(), Kirby\Toolkit\Str::endsWith(), Kirby\Toolkit\Str::encode(), Kirby\Toolkit\Str::ascii() #8138 #8147 #8145 #8158Kirby\Toolkit\A::without() #8146minWords/maxWords validators for non-single whitespace #8141Dir::remove() with atomic rename #6266panel.request.body(null) does not send "null" to the backend as the request body anymore #8016"false" to the backend anymore but instead omitted from the request. #8016Kirby\Toolkit\DateKirby\Toolkit\LayzValue: fixed passing variadic arguments #8139Kirby\Toolkit\A::implode(): preserve falsy values when imploding array #8140Kirby\Toolkit|Str::toBytes() #8159cookie.key optionI18n::template(): Prevent TypeError when $replace is null #8199[object Object] instead of the formatted link/email text. #7934max limit is reached #8232permissions extension has been deprecated. Those will be ignored in a future release, so make sure to define your custom permissions via the permissions extension. #8070Kirby\Text\KirbyTag::option() and Kirby\Text\KirbyTag::$options: Use $tag->kirby()->option() instead. #8196Kirby\Text\KirbyTags::parse(): $options parameter. Use new $debug parameter instead. #8196Kirby\Cms\LicenseStatus::Acknowledged and Kirby\Cms\LicenseType::Free cases #7832$helper.string.hasEmoji(): simplified regular expression #7966$helper.array #7977, $helper.regex #7976$helper.debounce/throttle #7980, $helper.isComponent #7982, $helper.embed #7983, $helper.keyboard #7984, $helper.isUploadEvent #7985, $helper.queue #7981, $helper.file #7990, $helper.field #7989, $helper.string #7979, $helper.link #7994, $helper.focus #7991, $helper.url #7992, $helper.page #7995, $library.colors #7997, $helper.clipboard #7988, $helper.upload #7996, dayjs plugins #8009, $helper.sort #7993History and Timer as helper class to TypeScript #8010 #8011this.$library, this.$helper and this.$esc are exposed in Vue SFC #8017RedirectError error class with support in panel.error() #8016Permissions::$actions property to $defaults; added separate protected array $actions populated by the constructorPermissions::setAll, Permissions::setCategory, Permissions::setCategories, Permissions::setAction, Permissions::hasAction, Permissions::hasCategory) with 4 cleaner ones: Permissions::normalize(), Permissions::expand(), Permissions::get(), Permissions::has()Permissions::normalize() and Permissions::expand() handle all four input shapes: null, bool, ['cat' => bool], ['cat' => ['action' => bool]], including wildcard at both levels.Permissions::for() now deprecates $category = null via Helpers::deprecated() and throws LogicException if a stored value is somehow not a boolarray_fill_keys(array_keys($defaults), false) instead of array_map(fn () => false, $defaults).<div> tags with <span> tags in <k-input> #8018Kirby\Template\Snippet::hasSlots() method #8178$debug parameter in Kirby\Text\KirbyTags::parse() #8196Html::rel() use #8142Kirby\Cms\Block::toHtml() now throws block snippet exceptions in debug mode instead of returning an inline Block error message. While this is technically a breaking change, we see this as a debugging enhancement which can clearly go into a minor release without negative impact for real-world projects.cpx for pinned composer dependencies shared between local dev and CIjsdom with happy-dom for frontend unit tests #7971Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
Kirby internally relies on the following values:
content.salt option is used to generate secure preview and media URLs that should not be guessable by external visitors.Kirby\Http\Cookie::$key property, to sign (or authenticate) cookie values to prevent easy tampering with cookie values that have been set from the backend.We recommend to set the content.salt and Kirby\Http\Cookie::$key values to long random strings for all of your sites.
We have updated the security guide with a section on this topic and added warnings to the Panel system view if Kirby detects the unchanged defaults.
Thanks to @adrgs and Peter Levashov (@petersevera) for their responsible disclosure and suggestion.
Forwarded, X-Client-IP or X-Real-IP headerThis vulnerability affects Kirby sites that have no configured user accounts and are running on publicly accessible servers behind a reverse proxy that sets the Forwarded: for=..., X-Client-IP, or X-Real-IP request header.
It was possible to install the Panel (= create the first admin user) in these setups even from remote IP addresses.
This vulnerability is of critical severity for affected sites.
Your site is not affected if any of the following apply:
X-Forwarded-For or Client-IP header instead of the affected ones.Advisory Details:
Thanks to Peter Levashov (@petersevera) for responsibly reporting the identified issue.
Dom::sanitize()This vulnerability affects Kirby sites and plugins that use the writer or list fields or that use $dom->sanitize(), Sane::sanitize(), Sane\Html::sanitize(), Sane\Svg::sanitize(), Sane\Xml::sanitize(), Sane::sanitizeFile() or $file->sanitizeContents() with untrusted input.
It was possible to inject malicious markup as children of an unknown HTML/XML tag, which would then be passed through Dom::sanitize() without being correctly sanitized according to the provided sanitization rules, causing a cross-site scripting (XSS) risk.
This vulnerability is of high severity for affected sites.
The default file upload protection is not affected, so sites that only validate uploaded files are not exposed to this vulnerability. The vulnerability can only be exploited by authenticated users.
Thanks to Shafiq Aiman (@shafiqaimanx) for responsibly reporting the identified issue.
This vulnerability affects Kirby sites that use the writer field in any blueprint.
It was possible to include a scripting link as the target of a link (or email link). This link target would then be clickable by the user who entered it.
A successful attack commonly requires knowledge of the content structure by the attacker as well as social engineering of a user with access to the Panel. The attack cannot be automated.
In Kirby's default configuration, the vulnerability is limited to self-XSS and cannot directly affect other users or visitors of the site. Panel plugins that are directly using the <k-writer> component may also be affected by stored XSS if they don't sanitize the resulting HTML before saving it to the content.
This vulnerability is of high severity for affected sites.
pages.access permission is not checked in the site/find REST API routeThis vulnerability affects all Kirby sites where users of a particular role have no permission to access pages (pages.access permission is disabled). This can be due to configuration in the user blueprint(s), options in the model blueprint(s), or a combination of both settings.
It was possible to retrieve page information (including full content and metadata) for arbitrary pages via the /api/site/find route without being authorized to access the respective pages.
This vulnerability is of high severity for affected sites.
Your Kirby sites are not affected if you intend all users of your site to be able to access all pages of the site. The vulnerability can only be exploited by authenticated users that know or guess the IDs or UUIDs of pages. Write actions as well as access to draft pages are not affected by this vulnerability.
Thanks to Rizky Muhammad (@EvidentObscurity) for responsibly reporting the identified issue.
Http\RemoteThis vulnerability affects Kirby sites and plugins that use the Kirby\Http\Remote class (including Remote::request(), Remote::get(), Remote::post(), and similar helpers) to send outgoing HTTP requests and that pass untrusted, user-controlled data into the headers option of such a request.
By including newline characters in the value of the header, it was possible to inject a separate, independent header that was not intended to be set.
A successful attack requires that an application or plugin forwards attacker-influenced input into a request header value. Sites that only send static, developer-defined headers are not affected. The attack does not target Panel users or site visitors directly; it targets the remote service that Kirby connects to.
In Kirby's default configuration, the Remote class is not exposed to untrusted input, so a default installation is not affected. The vulnerability becomes relevant for custom code, plugins, or integrations that build request headers from user input.
This vulnerability affects Kirby 5 sites that have the content.fileRedirects option enabled (set to true or a custom closure) as well as all Kirby 4 sites that haven't explicitly disabled this option.
It was possible to access clean file URLs of top-level drafts (e.g. /about-us/team.jpg) without providing authentication, without being authorized to access the top-level draft page, and without providing a valid preview token.
Sites on Kirby 5 using the default configuration are not affected by this vulnerability (the content.fileRedirects option is disabled by default since Kirby 5.0.0). It was also not possible to maliciously access clean file URLs for files stored in page drafts that are not on the top-level (such as /blog/article/resource.pdf).
Thanks to @adamyordan for responsibly reporting the identified issue.
pages.access permission is not checked in the pages picker for parent pagesThis vulnerability affects all Kirby sites that use the pages field and where users of a particular role have no permission to access pages (pages.access permission is disabled). This can be due to configuration in the user blueprint(s), options in the model blueprint(s), or a combination of both settings.
It was possible to confirm the existence of arbitrary pages and to retrieve the value of the title field of the pages found.
The vulnerability can only be exploited by authenticated users. Write actions are not affected by this vulnerability.
link and email marks of the writer field are now protected against self-cross site scripting (self-XSS) from inserted scripting linkspages field now consistently checks the pages.access permission for the provided parent pagesite/find API route are now filtered to only return pages that are accessible to the current user.content.fileRedirects is enabled.Forwarded: for=..., X-Client-IP or X-Real-IP request header with external IP address was provided by a reverse proxy.content.salt option and Cookie::$key default values have not been changed.$helper.url.hasDangerousScheme(url) JS helper$helper.string.isEmail(string, strict) helpercookie.key option to allow setting the Kirby\Http\Cookie::$key directly from the configKirby\Http\Environment now correctly extracts the for= value from the standardized Forwarded header, fixing ::isLocal() detection behind certain proxies. #8166->where() and ->having() clauses instead of simply dropping non-existing columns from those clauses #8180Kirby\Image\Focus::normalize() #8186(date:) KirbyTag now escapes its output to prevent HTML being injected through special characters in the tag value. Thanks to Peter Levashov (@petersevera) for his responsible disclosure and suggestion.Html::gist() now only embeds Gists from gist.github.com, so it can no longer load scripts from arbitrary URLs. Thanks to Peter Levashov (@petersevera) for his responsible disclosure and suggestion.Kirby\Image\QrCode::toSvg() #8185Kirby\Content\Lock::for() uses current language for fallback) #8173Kirby\Image\Location::num() through malformed EXIF data #8184Html::gist() (and the (gist:) tag) now ignores URLs from hosts other than gist.github.com. Sites embedding Gists from a custom host (e.g. GitHub Enterprise) can re-allow it via Kirby\Toolkit\Html::$gistDomains[] = 'gist.example.com';.Throw exceptions for UUID cache misses when content.uuid.index = false is set only in debug mode #8150
content.uuid.index = false is set only in debug mode #8150Nothing published for this version
Nothing published for this version
Compare
Compare
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
This is a backport of our security release for Kirby 5. For all details and vulnerabilities see: https://github.com/getkirby/kirby/releases/tag/5.6.0
We recommend all users upgrade to Kirby 5. If an upgrade is not possible, this security release is the alternative solution.
Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
This is a backport of our security release for Kirby 5. For all details and vulnerabilities see: https://github.com/getkirby/kirby/releases/tag/5.5.2
We recommend all users upgrade to Kirby 5. If an upgrade is not possible, this security release is the alternative solution.
Note This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getk…
Note
This release is part of our monthly security release series. Find out more about those releases and their background on our website: https://getkirby.com/buzz/security-update
This is a backport of our security release for Kirby 5. For all details and vulnerabilities see: https://github.com/getkirby/kirby/releases/tag/5.4.4
We recommend all users upgrade to Kirby 5. If an upgrade is not possible, this security release is the alternative solution.
Updated PHP and JS dependencies
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →