github getkirby/kirby 5.4.0

5 hours ago

🚨 Security

Server-Side Template Injection (SSTI) via double template resolution in option rendering

This vulnerability affects all Kirby sites that use option fields (checkboxes, color, multiselect, select, radio, tags or toggles) with options from a query or API whose values may not be fully trusted. It also affects direct uses of the OptionsApi or OptionsQuery classes of Kirby's Options package from plugin or site code. The attack requires either an
attacker in the group of authenticated Panel users or user interaction of another authenticated user.

This vulnerability is of high severity for affected sites.

Your Kirby sites are not affected if you are not using any of the mentioned fields or the Options package, if all options are defined statically in the blueprints or if all dynamically gathered options are to be trusted.

Thanks to @offset for responsibly reporting the identified issue.

Page, file and user creation APIs bypass create permission check via unfiltered blueprint parameter

This vulnerability affects all Kirby sites where users of a particular role have no permission to create pages, files or users (pages.create, files.create or users.create permission is disabled). This can be due to configuration in the user blueprint(s), via options in the model blueprint(s) or via a combination of both settings.

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 create pages, files and users. The vulnerability can only be exploited by authenticated users.

Thanks to @offset for responsibly reporting the identified issue.

pages.access/list and files.access/list permissions are not consistently checked in the Panel and REST API

This vulnerability affects all Kirby sites where users of a particular role have no permission to access or list pages or files (pages.access, pages.list, files.access or files.list permission is disabled). This can be due to configuration in the user blueprint(s), via options in the model blueprint(s) or via a combination of both settings.

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 and files of the site. The vulnerability can only be exploited by authenticated users.
Write actions are not affected by this vulnerability.

Read access to site, user and role information is not gated by permissions

This vulnerability affects all Kirby sites that might have potential attackers in the group of authenticated Panel users.

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 list and access the site model and all users and roles, including the content stored within these models.
Write actions are not affected by this vulnerability as they were gated by permissions before.

Thanks to @HuajiHD for responsibly reporting the identified issue.

XML Injection in the XML creator toolkit

This vulnerability only affects Kirby sites that use the Xml data handler (e.g. Data::encode($string, 'xml')) or the Xml::create(), Xml::tag() or Xml::value() method(s) in site or plugin code. The Kirby core does not use any of the affected methods.

If you use an affected method and cannot rule out input to these methods controlled by an attacker, we strongly recommend to update to a patch release.

Thanks to Patrick Falb (@dapatrese) at FORMER 03 for responsibly reporting the identified issue.

User avatar creation, replacement and deletion are not gated by user update permissions

This vulnerability affects all Kirby sites where users of a particular role have no permission to update user information (user.update or users.update permission is disabled). This can be due to configuration in the blueprint(s) of the acting users, via options in the blueprint(s) of the target users or via a combination of both settings.

Your Kirby sites are not affected if you intend all users of your site to be able to upload, replace or delete user avatars. The vulnerability can only be exploited by authenticated users.

Page creation API bypasses changeStatus permission check via unfiltered isDraft parameter

This vulnerability affects all Kirby sites where users have the permission to create pages (pages.create permission is enabled) but not the permission to change the status of pages (pages.changeStatus permission is disabled). This can be due to configuration in the user blueprint(s), via options in the page blueprint(s) or via a combination of both settings.

Your Kirby sites are not affected if your use case does not consider the creation of published pages a malicious action. The vulnerability can only be exploited by authenticated users.

Thanks to @offset for responsibly reporting the identified issue.

System API endpoint leaks installed version and license data to authenticated users

This vulnerability affects all Kirby sites that might have potential attackers in the group of authenticated Panel users.

Thanks to @HuajiHD and @0x-bala for responsibly reporting the identified issue.

✨ Enhancements

  • Site permissions
    • New access permission for the site
    • New Kirby\Cms\Site::isAccessible() method checking if the current user has access permission for the site
    • New static Kirby\Cms\Find::site() method returning the site object or throwingKirby\Exception\NotFoundException if the site is not accessible
    • New i18n string error.site.notAccessible added to i18n/translations/en.json
  • User permissions
    • New access and list permissions for users and the current user.
    • New Kirby\Cms\User::isAccessible() method checking if the current user has access permission for a given user
    • New Kirby\Cms\User::isListable() method checking if a user is both accessible and has list permission. Inaccessible users are implicitly not listable
    • New static Kirby\Cms\Find::users() method returning only users filtered by isListable()
  • Role permissions
    • New Kirby\Cms\Role::isAccessible() method checking if the current user has users.access or user.access permission. If the role is the same role as the user's, the user.access permissions are checked. Otherwise users.access.
    • New static Kirby\Cms\Find::role() and Kirby\Cms\Find::roles() methods returning only roles filtered by isAccessible()
    • Added a new error.role.notFound translation key.
  • Avatar permissions
    • New avatar hooks user.createAvatar, user.replaceAvatar, user.deleteAvatar (including :before and :after)
    • New User class methods: User::createAvatar(), User::replaceAvatar(), User::deleteAvatar()
    • New User rules: UserRules::createAvatar(), UserRules::replaceAvatar(), UserRules::deleteAvatar(), UserRules::validAvatar()

🚨 Security fixes

  • The GET /system API route now consistently filters the relevant set of information by current system state
  • Kirby\Cms\Find::parent() now uses Kirby\Cms\Find::site() instead of $kirby->site() for the site model lookup
  • Kirby\Cms\Api::site() now delegates to Kirby\Cms\Find::site() instead of $this->kirby->site()
  • config/api/models/System.php the title field now reads directly from $this->kirby()->site() to bypass the site.access permission check, ensuring the title is always available
  • The page.move dialog now uses Kirby\Cms\Find::site() in the submit handler, when a page gets moved to the top-level
  • Kirby\Cms\Find::user() now enforces isAccessible() on the resolved user, throwing Kirby\Exception\NotFoundException if the user exists but is inaccessible
  • API routes (config/api/routes/users.php): all $this->user() / $this->users() calls replaced with Kirby\Cms\Find::user() / Kirby\Cms\Find::users() to apply access control at the API layer. Also cleans up the /roles route and the change-password logic to use Kirby\Cms\Find
  • Kirby\Cms\Api::users() delegates to Kirby\Cms\Find::users() instead of $this->kirby->users()
  • Kirby\Cms\UserPicker filters out non-listable users before search/sort
  • Kirby\Panel\Collector\UsersCollector filters out non-listable users before role filtering and pagination
  • Kirby\Panel\Controller\Search::users() filters by isListable before running the search query. Also moves filter('isListable') before search() in the pages search for consistency
  • Kirby\Panel\User::prevNext() prev/next navigation now filters siblings by isListable so navigation skips hidden users
  • The API User model now filters siblings by isListable for prev and next user.
  • The model methods in the Kirby\Panel\ChangesDialog class (::files(), ::users(), ::pages()) will now filter by unlistable models to make sure that they don't accidentally appear in the dialog.
  • Kirby\Cms\UserPicker now filters inaccessible users for the picker dialog.
  • Updated Kirby\Cms\Roles::canBeCreated() and Kirby\Cms\Roles::canBeChanged() to run filter('isAccessible', true) before the existing filter so inaccessible roles are
    excluded even if they would otherwise pass the create or changeRole permission checks
  • Updated Kirby\Cms\User::roles() to apply filter('isAccessible', true) to the full roles collection before any further permission checks so unauthenticated users and users without user access permissions get no roles.
  • config/api/routes/roles.php: Replaced direct $kirby->roles() calls with Find::roles() so all roles API endpoints enforce access filtering. Replaced $kirby->roles()->find($name) with Find::role($name) for the single-role endpoint. Replaced $kirby->request()->get('canBe') with $this->requestQuery('canBe') for consistency
  • config/api/models/User.php: Added an extra filterBy('isAccessible', true) call on the roles field of the user API model to ensure the API response never exposes inaccessible roles
  • user.update permissions are now required to create, replace or delete a user avatar.

🚨 Breaking changes

  • The pages.changeStatus permission now also takes effect during the creation of pages (by preventing the creation of published pages instead of drafts). If you need the old behavior of allowing the creation of published pages but preventing users from changing the status of existing pages, please enable the changeStatus permission and block changes to existing pages in a page.changeStatus:before hook.

♻️ Refactored

  • The methods $page->copy() and $page->changeNum() have been marked as internal. They should only be called after all necessary checks (e.g. permissions) have been performed.
  • Replace deprecated calls to $form->values()
  • Remove dead code (next/prev) in the page API model

Don't miss a new kirby release

NewReleases is sending notifications on new releases.