5.3.0 (unreleased)
Overview
Security considerations
Three security fixes that were previously released in the July security release are mentioned in the Silverstripe CMS security patches July 2024 blog post are listed below.
Review the individual vulnerability disclosure for more detailed descriptions of each security fix. We highly encourage upgrading your project to include the latest security patches.
We have provided a severity rating of the vulnerabilities below based on the CVSS score. Note that the impact of each vulnerability could vary based on the specifics of each project. You can read the severity rating definitions in the Silverstripe CMS release process.
- CVE-2024-29885 - Reports are still accessible even when canView is set to false Severity: Medium
- CVE-2024-32981 - XSS Vulnerability with text/html base64-encoded payload Severity: Medium
- SS-2024-001 - TinyMCE allows svg files linked in object tags Severity: Medium
Features and enhancements
Changes to TinyMCEConfig
In order to facilitate fixing a bug related to the sanitisation of HTML content via the HTMLEditorSanitiser
class, some changes had to be made to the TinyMCEConfig
class. Those changes are as follows:
- If
valid_elements
andextended_valid_elements
are both empty, all HTML elements will be stripped out of the HTML content. - A default set of
valid_elements
has been defined for allTinyMCEConfig
instances. If you use customTinyMCEConfig
definitions and have not explicitly set thevalid_elements
option, you may have more elements permitted than you were expecting. - There is a new
TinyMCEConfig.default_options
configuration property which allows you to define the default options for allTinyMCEConfig
instances.
If you use custom TinyMCEConfig
definitions, we strongly recommend double checking if they include a definition of valid_elements
, and if they don't, validate whether the default set defined in TinyMCEConfig.default_options
is suitable for you.
You can either change the TinyMCEConfig.default_options
configuration value to affect the options for all TinyMCEConfig
definitions, or explicitly define valid_elements
for your specific configuration instances. See setting options for more details.
See sanitisation of HTML for more information about the bug that was fixed.
High-level API for converting files
There is now a high-level API for converting files from one format to another. This builds on top of the low-level API which was added in 5.2.0.
Files can be converted both in PHP code and in templates:
// Convert an image to webp format and apply the FitMax manipulation to the result
$this->MyImage()->Convert('webp')->FitMax(100, 100);
<%-- Convert an image to webp format and apply the FitMax manipulation to the result --%>
$MyImage.Convert('webp').FitMax(100, 100)
Out of the box silverstripe/assets
provides the new InterventionImageFileConverter
class which converts images to other image formats using Intervention Image. You can add your own FileConverter
implementations in projects or modules for any file convertions you might need.
See convert a file to a different format for more details.
Improve customisability of rendered images
We've aligned how images added to an HTMLEditorField
and images invoked in templates are rendered. The markup up for both <img>
tags are now generated from the same template file. This makes it easier to customise how images are rendered on your site.
The template for this is templates/SilverStripe/Assets/Storage/DBFile_Image.ss
. Add a file with that path to your Silverstripe CMS theme if you want to override it.
This opens many interesting possibilities. For example, this code snippet will provide a WebP version of any image rendered on your site.
<picture>
<source srcset="$Convert('webp').Link" type="image/webp">
<img $AttributesHTML >
</picture>
You can also choose to have different rendering logic for HTMLEditorField
images and for images invoked in templates by overriding different templates.
- Add a
SilverStripe/Assets/Shortcodes/ImageShortcodeProvider_Image.ss
to your theme to control images added to an HTMLEditorField. - Add a
DBFile_Image.ss
file to the root of your theme to control only images invoked in templates.
Validation for inline-editable elemental blocks
Elemental content blocks now support validation when saving or publishing individual content blocks using the "three-dot" context menu in the top-right of the block.
Validation can be added to a content block using standard Model Validation and Constraints by implementing a DataObject::validate()
method on a content block, or by using Form Validation where there are several options available.
Elemental data is no longer sent when saving the parent DataObject
(usually a Page
) that contains an ElementalAreaField
. Instead, when saving the parent DataObject
, all the child inline-editable elements that have unsaved changes are inline saved at the same time. This change was done to consolidate the saving process down to a single code path. The code that was previously used to process any element data sent with the parent data has been removed.
FormField
scaffolding for DataObject
models
We've made a few improvements to how form fields are scaffolded for DataObject::getCMSFields()
.
Define scaffolded form fields for relations
Most DataObject
classes will rely on some amount of automatic scaffolding of form fields in their getCMSFields()
implementations. However, it's common for modules to provide a specialised form field which is intended to always be used with a specific DataObject
class. In those cases, even though you always want to use that form field with that class, you have to copy some boilerplate code from the module's documentation to set it up.
You can now define what form fields should be used when scaffolding form fields for has_one
, has_many
, and many_many
relations. This is defined on the class on the child-side of the relationship. For example, for the below has_one
relation you would implement scaffoldFormFieldForHasOne()
on the MyChild
class.
namespace App\Model;
use SilverStripe\ORM\DataObject;
class MyParent extends DataObject
{
// ...
private static array $has_one = [
'MyChild' => MyChild::class,
];
}
namespace App\Model;
use SilverStripe\Forms\FormField;
use SilverStripe\ORM\DataObject;
class MyChild extends DataObject
{
// ...
public function scaffoldFormFieldForHasOne(
string $fieldName,
?string $fieldTitle,
string $relationName,
DataObject $ownerRecord
): FormField {
return /* instantiate some FormField here */;
}
}
This means modules can pre-define the form field that should be used for their custom models, which reduces the amount of boilerplate code developers need to include in their getCMSFields()
implementations.
For more information see scaffolding for relations.
FormScaffolder
options
The FormScaffolder
class (which is responsible for scaffolding form fields for getCMSFields()
) has some new options:
option | description |
---|---|
mainTabOnly | Only set up the "Root.Main" tab, but skip scaffolding actual form fields or relation tabs. If tabbed is false, the FieldList will be empty. |
ignoreFields | Deny list of field names. If populated, database fields and fields representing has_one relations which are in this array won't be scaffolded. |
ignoreRelations | Deny list of field names. If populated, form fields representing has_many and many_many relations which are in this array won't be scaffolded. |
restrictRelations | Allow list of field names. If populated, form fields representing has_many and many_many relations not in this array won't be scaffolded. |
In particular, the ignoreFields
and ignoreRelations
options are useful ways to prevent form fields from being scaffolded at all. You can use this instead of calling $fields->removeFieldByName()
, for example if you are adding database fields that you don't want to be edited with form fields in the CMS.
These options are now also configurable using the new DataObject.scaffold_cms_fields_settings
configuration property.
See the scaffolding section for more details.
Support for JOIN
in SQL UPDATE
The SQLUpdate
class now supports all of the same JOIN
operations (using the same methods) that SQLSelect
does.
This is particularly helpful if you need to update columns in one table to match values from another table.
Autologin token regeneration changes
The Autologin ('remember me') feature stores cookies in the user's browser to allow recreation of their session when it expires. Currently, one of the cookies is regenerated whenever a user's session is recreated. This can cause unexpected logouts in certain situations, and has minimal value from a security standpoint.
In 5.3, the current behaviour is retained, but can be disabled via configuration:
SilverStripe\Security\RememberLoginHash:
replace_token_during_session_renewal: false
This will cause the token to be generated once during login, and not be regenerated during session renewal.
From 6.0 onwards, tokens will never be regenerated during session renewal, and this configuration will be removed.
Other new features
silverstripe/linkfield
now has improved accessibility support for screen readers and keyboard navigation. Focus states have also been made consistent between keyboard and mouse interaction.silverstripe/graphql-devtools
contains a newGraphQLSchemaInitTask
to help you initialise a basic GraphQL schema.GridFieldDetailForm_ItemRequest
now uses aPjaxResponseNegotiator
to handle PJAX responses for the save and publish actions. This aligns it with responses from other form submissions in the CMS.- Primitive types inside an iterable object will now be automatically converted to relevant
DBField
types so can be rendered in a template. This allows the use ofreturn ArrayList::create(['lorem', 123]);
from aContentController
method that is then looped over in a template. - A new
TabSet::changeTabOrder()
method has been added that allows you to change the order of tabs in aTabSet
. See tabbed forms for details.
API changes
- Passing a non-array
$fields
argument to bothFieldList::addFieldsToTab()
andFieldList::removeFieldsFromTab()
has been deprecated. - The
BaseElement::getDescription()
method has been deprecated. To update or get the CMS description of elemental blocks, use thedescription
configuration property and the localisation API. -
The
RememberLoginHash::renew()
method has been deprecated without replacement, since the associated behaviour will be removed in 6.0.- The
onAfterRenewToken
extension point within this method will likely be replaced with a new extension point in 6.0.
- The
- The
RememberLoginHash.replace_token_during_session_renewal
configuration property has been added to allow disabling token regeneration during session renewal. This property will be removed in 6.0. - Code for the CMS GraphQL
admin
schema which provided endpoints for the CMS has been deprecated and will be removed in CMS 6. Functionality which the GraphQL endpoints are currently responsible for will be replaced with regular Silverstripe controller endpoints instead. Extension hooks will be added to the new controller endpoints that return data to allow for customisation. Frontend schemas, such thedefault
schema, will continue to work in CMS 6. IPUtils
has been deprecated and its usage has been replaced with theIPUtils
class fromsymfony/http-foundation
which is now included as a composer dependency insilverstripe/framework
.- Code in
silverstripe/blog
which supported integration withsilverstripe/widgets
has been deprecated and will be removed in CMS 6.0. DataExtension
,SiteTreeExtension
, andLeftAndMainExtension
have been deprecated and will be removed in CMS 6.0. If you subclass any of these classes, you should now subclassExtension
directly instead.
Bug fixes
- If you use
<% loop %>
in your templates without telling it what to loop, previously the behaviour was to fail silently. This will now loop over what is currently in scope. See looping over lists for more details. - Reordering elemental blocks used to update the published sort order immediately, without pressing the publish button. That wasn't consistent with the way any other sort order updates happen in the CMS. We've changed this so that the sort order won't update in your published site until you publish one of the blocks in the elemental area that the reordered blocks live in. This is consistent with what happens when you reorder pages in the site tree.
This release includes a number of bug fixes to improve a broad range of areas. Check the change logs for full details of these fixes split by module. Thank you to the community members that helped contribute these fixes as part of the release!
Sanitisation of HTML
When you save content in a HTMLEditorField
, the HTMLEditorSanitiser
class is responsible for ensuring the HTML content is safe and matches the valid_elements
and extended_valid_elements
options you've defined.
There was a bug that resulted in HTMLEditorSanitiser
using the 'active' HTMLEditorConfig
instance rather than the instance which was defined for the field. In many cases this goes unnoticed because the default active instance is very permissive, and TinyMCE does a lot of this work on the client-side, but it was possible to bypass the defined allowed HTML elements by sending requests directly to the server.
This bug has been fixed, but some additional changes were required to facilitate it. See changes to TinyMCEConfig
for more details about those changes.
Restore batch action removed
The "Restore" batch action was removed from the batch actions dropdown menu in the CMS as it has not functioned correctly for a long time. There is no intention at this stage to reintroduce this feature.