Version 4 supported
This version of Silverstripe CMS is still supported though will not receive any additional features. Go to documentation for the most recent stable version.



Security patches

This release contains security patches. Some of those patches might require some updates to your project.

CVE-2020-9309 script execution on protected files

Silverstripe can be susceptible to script execution from malicious upload contents under allowed file extensions (for example HTML code in a TXT file). When these files are stored as protected or draft files, the MIME detection can cause browsers to execute the file contents.

Risk factors

If your project already includes the silverstripe/mimevalidator module, it's already protected. CWP projects are already protected.

If your project includes the silverstripe/userforms module or allows anonymous users to upload files, it's at a higher risk because malicious users can create files without requiring a CMS access.

Actions you need to take

Upgrading to silverstripe/recipe-core 4.6.0 will automatically install the silverstripe/mimevalidator module.

Read MIME validator is now part of recipe-core to understand how this will impact your project.

CVE-2019-19326 web cache poisoning

Silverstripe sites using HTTP cache headers and HTTP caching proxies (e.g. CDNs) can be susceptible to web cache poisoning through the:

  • X-Original-Url HTTP header
  • X-HTTP-Method-Override HTTP header
  • _method POST variable.

In order to remedy this vulnerability, Silverstripe Framework 4.6.0 removes native support for these features. While this is technically a semantic versioning breakage, these features are inherently insecure and date back to a time when browsers didn't natively support the full range of HTTP methods. Sites who still require these features will have highly unusual requirements that are best served by a tailored solution.

Re-enabling the support for removed features

These features are best implemented by defining a Middleware.

The following example illustrates how to implement an HTTPMiddleware that restores support for the X-Original-Url header and the _method POST parameter for requests originating from a trusted proxy.

namespace App\Middleware;

use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\Middleware\HTTPMiddleware;

 * This is meant to illustrate how to implement an HTTPMiddleware. If you blindly
 * copy-paste this in in your code base, you'll simply replicate the vulnerability.
class InsecureHeaderMiddleware implements HTTPMiddleware
    public function process(HTTPRequest $request, callable $delegate)
        // Normally, you would validate that the request is coming from a trusted source at this point.
        // View SilverStripe\Control\Middleware\TrustedProxyMiddleware for an example.
        $trustedProxy = true;

        if ($trustedProxy) {
            $originalUrl = $request->getHeader('X-Original-Url');
            if ($originalUrl) {
                $_SERVER['REQUEST_URI'] = $originalUrl;

            $methodOverride = $request->postVar('_method');
            $validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'];
            if ($methodOverride && in_array(strtoupper($methodOverride), $validMethods)) {

        return $delegate($request);

To learn more about re-implementing support for the disabled features:

CVE-2020-6164 information disclosure on /interactive URL path

A specific URL path configured by default through the silverstripe/framework module can be used to disclose the fact that a domain is hosting a Silverstripe application. There is no disclosure of the specific version. The functionality on this URL path is limited to execution in a CLI context, and is not known to present a vulnerability through web-based access. As a side-effect, this preconfigured path also blocks the creation of other resources on this path (e.g. a page).

CVE-2020-6165 limited queries break CanViewPermissionChecker

The automatic permission checking mechanism in the silverstripe/graphql module does not provide complete protection against lists that are limited (e.g. through pagination), resulting in records that should fail the permission check being added to the final result set.

If your project implements custom GraphQL queries using the CanViewPermissionChecker, you should validate that they still work as expected after the upgrade.

Read Controlling who can view results in a GraphQL result set for more information on updating your GraphQL queries.

MySQL tables are auto-converted from MyISAM to InnoDB

Beginning with 4.4.0, our minimum requirement for MySQL is 5.6 (since MySQL 5.5 end of life reached in December 2018). Starting with MySQL 5.6, InnoDB is the new default storage engine, replacing the older MyISAM engine.

Silverstripe CMS already creates InnoDB tables by default, mainly in order to benefit from their better support for database transactions. Before MySQL 5.6, InnoDB didn't have a FULLTEXT search index, requiring us to enforce the MyISAM engine when devs opted into this index type in their particular setup. There are a few ways in which this opt-in can happen:

  • Adding the FulltextSearchable extension to a DataObject, as described in our search docs
  • Defining 'type' => 'fulltext' in DataObject::$db column definitions
  • Implementing DBIndexable on a custom DBField subclass.
  • Setting 'ENGINE=MyISAM' in DataObject::$create_table_options

This search index is not required to enable simple text search in the "Pages" section of the CMS, or any ModelAdmin implementations. We generally recommend to choose a more powerful search addon (e.g. based on Solr or ElasticSearch) for website frontend search use cases.

As of 4.6.0, a dev/build will automatically switch MyISAM tables to InnoDB, which automatically recreates any indexes required. If you have large indexes, this can extend the duration if this task. As usual, back up your database before upgrading, and test upgrades on non-production systems first. Our tests indicate that indexes with thousands of records and screen pages worth of content (15MB index size) are converted in a few seconds.

In order to opt out of this change, you can set the engine explicitly for your DataObject implementations:

namespace App\Model;

use SilverStripe\ORM\Connect\MySQLSchemaManager;
use SilverStripe\ORM\DataObject;

class MyDataObject extends DataObject
    private static $create_table_options = [
            MySQLSchemaManager::ID => 'ENGINE=MyISAM',

Editing files directly in the insert media modal

Authors can now directly edit file details when selecting a file in an UploadField or when inserting media in a HTMLEditorField. The "image placement" and "file link" forms that show when inserting an image or a link in an HTMLEditorField have been simplified.

If you have customised the fields in the asset administration UI or Insert Media modal, you will need to do some regression testing when upgrading, and will likely need to make some minor adjustments to your code.

Implementing the new Edit Details UI required filtering the fields generated in File::getCMSFields() into two Forms. The implementation in 4.6.0 does not expose a clear API to custom fields for differentiating between the Forms, and by default any fields added via an extension will appear in both views. For the time being, a simple way to resolve this is to check for the presence of the Editor.Details.Title field and add your field based on this. See the community module jonom/focuspoint for an example implementation, and ensure you update this module during your upgrade to 4.6.0 if you have it installed.

We intend to improve this pattern in a future release of Silverstripe CMS.

MIME type validation now a core module

The Silverstripe CMS installer now includes the silverstripe/mimevalidator. This change was implemented to address CVE-2020-9309 vulnerability and the inherent limits of controlling allowed file types by looking only at file extensions.

For most Silverstripe CMS projects, this will be a transparent upgrade. However, they are some situations where you might need to make some adjustments.

Who will get MIME validator installed automatically?

If your Silverstripe CMS project references silverstripe/recipe-core or silverstripe/recipe-cms in its composer.json file, silverstripe/mimevalidator will be automatically installed once you upgrade to Silverstripe CMS 4.6.0. Those recipes might also be indirectly installed via other recipes (e.g: cwp/cwp-recipe-core). You can run this command from your project root to know for sure:

composer show silverstripe/recipe-core

If you get an error, you will not be automatically get silverstripe/mimevalidator following your upgrade.

After upgrading your project, composer should automatically create the following file in your project: app/_config/mimevalidator.yml. This file contains the default configuration for the new module. You'll need to commit mimevalidator.yml and your updated composer.json file to your source control system.

If you're not using recipe-core/recipe-cms?

If your project doesn't reference silverstripe/recipe-core or silverstripe/recipe-cms, you will need to manually add silverstripe/mimevalidator to your project dependencies. Run this command to install silverstripe/mimevalidator:

composer require silverstripe/mimevalidator

Then, add this code snippet to your YAML configuration to enable MIME type validation:

    class: SilverStripe\MimeValidator\MimeUploadValidator

Customising allowed file types

If you've customised your project allowed file types, you might need to tweak the boilerplate MIME validator configuration and confirm the new module doesn't interfere with your existing logic.

Read Allowed file types in the Silverstripe CMS documentation to learn how to Control the type of files that can be stored in your project.

What if the MIME validator module is already installed?

If your project already requires silverstripe/mimevalidator, you probably don't need to do anything.

If you didn't have a pre-existing app/_config/mimevalidator.yml file and your MIME validator configuration is contained somewhere else in your project, feel free to discard mimevalidator.yml.

If you explicitly required silverstripe/mimevalidator in your composer.json file, you can remove the explicit reference and rely on the module being installed via the recipes.

If your version constrain for silverstripe/mimevalidator in your composer.json is too strict, you might get an error while upgrading to the latest version of recipe-core. If this occurs, either loosen the constraint for silverstripe/mimevalidator or remove it altogether.

What if I don't want the MIME validator module?

This is not advise, but you can upgrade to Silverstripe CMS 4.6.0 without installing the silverstripe/mimevalidator module.

To achieve this, you will need to "inline" recipes in your composer.json. This means you will have an explicit dependency for each individual Silverstripe CMS module. You can inline recipes by running this command.

composer require-recipe silverstripe/recipe-cms

Then you just need to remove the reference to silverstripe/mimevalidator.

Beware that this will make future upgrade more difficult because you will have to manually edit each module constraint.

File indicators in the file manager

File indicators

Files and folders with permissions of either "Logged in users" or "Only these groups (choose from list)" now show a "Restricted access" icon in the file manager. These permissions can either be directly on the DataObject or they can be inherited from the parent folder.

Websites with the optional UserForms module installed will show a "Form submission" icon on files uploaded through a UserForm. UserForm uploaded files without a "Restricted access" icon show a "Form submission, unrestricted access" icon instead. For more information about File indicators and how they work in conjunction with UserForms and the File manager refer to Silverstripe CMS User help guides.

Solr no longer indexes draft/restricted content

At the time of this release a new version of the popular silverstripe/fulltextsearch module is also available, introducing more secure defaults. Most notably, draft and restricted content will no longer be indexed by default, due to a canView() check being performed against an anonymous user prior to (re)indexing. Restricted content means that it has a permission level of either 'Logged-in users' or 'Only these groups'.

If your project uses this module, after upgrading your website, ensure that you run the Solr_Reindex task on your production environment to remove previously indexed content that should no longer be there.

If your website requires draft or restricted content to be indexed, you can opt-out of the new secure defaults on a per-model basis.

This is a great opportunity to make sure that any custom indexes/search controllers in your project are correctly filtering results based on permissions and search visibility, which you can now achieve via a unified method (see SilverStripe\FullTextSearch\Search\Services\SearchableService::isSearchable().)

The silverstripe/fulltextsearch module readme provides additional information.

Simplify customisation of ModelAdmin

ModelAdmin::getEditForm() has been split into smaller more discrete protected methods:

  • getGridField()
  • getGridFieldConfig().

Two matching extension hooks have been added as well:

  • updateGridField()
  • updateGridFieldConfig().

This will make it easier for developers to customise GridFields in their ModelAdmins.

Learn how to alter the ModelAdmin GridField or Form

Login forms module ships with installer

The silverstripe/login-forms module is now part of the default installer. This alters the login form to provide consistent styling and behaviour that's independent from the specifics in your project. Only new projects will get the new login form. Older projects can manually require the silverstripe/login-forms module to get the new login form.

View the Silverstripe Login Forms readme on GitHub for more details.

PHP 7.4 compatibility

This release supports PHP 7.4, as does version 4.5.3 which was released at the same time. At the time of this release, all commercially supported modules also support PHP 7.4.


Change log


  • 2020-05-13 996c1b571 Remove/deprecate unused controllers that can potentially give away some information about the underlying project. (Maxime Rainville) - See cve-2020-6164
  • 2020-05-11 71db45b18 Stop honouring X-HTTP-Method-Override header, X-Original-Url header and _method POST variable. Add SS_HTTPRequest::setHttpMethod() (Maxime Rainville) - See cve-2019-19326
  • 2020-03-08 6779fd3 Add FolderMigrationHelper (Serge Latyntcev)
  • 2020-02-17 6c3a619 Move the query resolution after the DataListQuery has been altered (Maxime Rainville) - See cve-2020-6165
  • 2020-02-11 044eb43 Ensure canView() check is run on items (Steve Boyd) - See cve-2020-6165

API changes

  • 2020-05-28 422a9a2 Bump to require 4.6.x-dev branches (Steve Boyd)
  • 2020-04-28 df8004b Bump @silverstripe/webpack-config to 1.5.0 (Maxime Rainville)
  • 2020-04-24 d513932 Bump @silverstripe/webpack-config to 1.5.0 (Maxime Rainville)
  • 2020-04-17 99eeb59 Add new updateResponse hook to allow extension to update the response (Maxime Rainville)
  • 2020-02-14 29943f904 TestSession request methods now use the correct HTTP method (#8987) (Garion Herman)
  • 2019-11-20 0c9be1b Add updateGridFieldConfig and updateGridField hooks to ModelAdmin (Maxime Rainville)
  • 2019-11-19 ba831dc Break up ModelAdmin::getEditForm into getGridField and getGridFieldConfig (Maxime Rainville)
  • 2019-10-16 67398ed Add Silverstripe specific button UI (Maxime Rainville)

Features and enhancements

  • 2020-06-12 ae97a20 Update gridfield sort to use text default on focus (#1055) (Sacha Judd)
  • 2020-06-12 05e0e5c Update draft state indicator on thumbnails to use correct background colour (#1104) (Sacha Judd)
  • 2020-05-25 5a1b634 Add new variations of block icons and update existing (Sacha Judd)
  • 2020-05-25 da241a2 Add file status icons to file manager (#1087) (Steve Boyd)
  • 2020-05-25 d93d63b Add FileStatusIcon component (#1033) (Steve Boyd)
  • 2020-05-21 5220dc1 Separate storybook icons into different sections for people to easily see where different icons belong (Scott Hutchinson)
  • 2020-05-21 239c559 Methods to support file status icons (Steve Boyd)
  • 2020-05-11 39f3032 Add Bootstrap Tooltip support outside of React contexts (Garion Herman)
  • 2020-05-08 0874950 Add MIME type validation out of the box (Maxime Rainville)
  • 2020-05-04 4ba8a7e Enable TreeDropdownField in pattern library, reorder addon tabs (Garion Herman)
  • 2020-05-01 77b896f Add mid-blue colour, update info elements to match designs (Garion Herman)
  • 2020-04-15 daa80d8 Add secure icons (Sacha Judd)
  • 2020-04-06 c6b698cb0 Allow InnoDB for FULLTEXT indexes (Ingo Schommer)
  • 2020-04-04 2bbc280c Remove unused $controller from lambda function (mattclegg)
  • 2020-04-02 b664b8d Boot typenames outside graphql request (#254) (Aaron Carlino)
  • 2020-03-24 1fb574a5b Variadic URL parameter matches for url_handlers (#9438) (Daniel Hensby)
  • 2020-03-13 159a42a Allow instance override of CORS config (Aaron Carlino)
  • 2020-02-14 30c3b127c Add ClassInfo method to get all classes with a given extension applied (Michal Kleiner)
  • 2020-01-24 82387cb4 Add extension hook updateRedirectionLink() (#2518) (Guy Marriott)
  • 2020-01-24 6ee17a83 Add extension hook updateRedirectionLink() (Will Rossiter)
  • 2019-12-17 5449014 Update language and conditions in BulkDeleteConfirmation (Garion Herman)
  • 2019-12-16 a54fff8 add option to prevent InterventionBackend cache flush + task (Christopher Darling)
  • 2019-12-09 0eed58a Export url lib in admin vendor bundle (Maxime Rainville)
  • 2019-11-18 688890146 Update docs to be compliant with Gatsby site (#9314) (Aaron Carlino)
  • 2019-07-05 9171342 Add silverstripe/login-forms (Ingo Schommer)
  • 2019-02-23 9d1d59d8d Accept / as designation for root URL controller (Garion Herman)
  • 2019-02-07 54a3649 Apply versioned filters to reading state (Ingo Schommer)


  • 2020-06-05 d7ed6e3 ImageShortcodeProvider follow FileShortcodeProvider session access grant policy (#402) (Serge Latyntsev)
  • 2020-06-01 3df2222 Prevent react-selectable from interfering with pagination (Maxime Rainville)
  • 2020-05-28 43c119b Require frameworktest for behat test (#261) (Maxime Rainville)
  • 2020-05-27 27231bf Treat login-forms as a core module (Maxime Rainville)
  • 2020-05-26 3e52b1a Vertically align form description contents (including icons) (bergice)
  • 2020-05-26 09d2061 Asset revision timestamps are no longer underlined in asset admin history tabs (Robbie Averill)
  • 2020-05-25 32e7b46 Make sure the new mime validator config does not clash with the cwp config (#54) (Maxime Rainville)
  • 2020-05-19 b9de9e6 Remove direct descendant selector to apply correct margins (Sacha Judd)
  • 2020-05-13 b1b61f866 Set nonce style on unit tests (Steve Boyd)
  • 2020-05-11 9dcc030 Resize address-card-warning (Sacha Judd)
  • 2020-05-08 afc1759 Page search form layout overflow issue (Mojmir Fendek)
  • 2020-05-05 2cc037b Fix merge conflict in Travis configuration (Robbie Averill)
  • 2020-05-01 e344b66db Fixed broken link to the module creation docs (Dustin Quam)
  • 2020-05-01 b1f6e52 Remove grid view sorting hack to correct initial state (Garion Herman)
  • 2020-05-01 891f0682 Correct placement of 'Page location' field title (Garion Herman)
  • 2020-04-30 fff806ca Prevent Treeview from always reloading (Maxime Rainville)
  • 2020-04-29 ed4c436 built dist files (Niklas Forsdahl)
  • 2020-04-27 5bcc574 GET parameter handling in GridField reload (Niklas Forsdahl)
  • 2020-04-27 eac547a Grid field reload always triggers change event if request has GET parameters (Niklas Forsdahl)
  • 2020-04-21 bb0fc12 Stops an image's "Title text (tooltip)" being set to the filename by default (#1058) (James Cocker)
  • 2020-04-20 080ce157c Fix various typos in comments (Daniel Hensby)
  • 2020-04-18 216989165 Ensure realpath returns a string for stripos (mattclegg)
  • 2020-04-15 be80813 Campaign admin permission fix (Mojmir Fendek)
  • 2020-04-15 d7c76bdb Published pages filter correction (missing default filter) (Mojmir Fendek)
  • 2020-04-14 e2a6281 Legacy max upload size setting removal (Mojmir Fendek)
  • 2020-04-10 ab87bdc04 Fix SS_BASE_URL logic when undefined and docroot without public folder (Michal Kleiner)
  • 2020-04-09 a50e15e5e Avoid VACUUM on test dbs in Postgres (Ingo Schommer)
  • 2020-04-08 2c5deceeb Filter out all FULLTEXT BOOLEAN chars (Ingo Schommer)
  • 2020-04-08 e51bd421 InnoDB FULLTEXT compat in tests (Ingo Schommer)
  • 2020-04-08 dd839ca2 Remove searchEngine() test that's using API wrong (Ingo Schommer)
  • 2020-04-08 052c5cbc3 Infinite loops in TempDatabase (fixes #8902) (Ingo Schommer)
  • 2020-04-05 d6fc7fe80 Fix issue with the GridField documentation - many_many_extraFields code example (tdenev)
  • 2020-04-02 9e0ed0a50 Fix spaces around concatenation operator (Dan Hensby)
  • 2020-03-23 5002f514b Capitalisation fixes in welcome back message (#9439) (Robbie Averill)
  • 2020-03-23 e5aa94c "My profile" title in CMS is now vertical centered as other LeftAndMain screens are (Robbie Averill)
  • 2020-03-20 14fd29a Switch incorrect modified and draft state indicator colours (Sacha Judd)
  • 2020-03-18 fe5f965 Update FileIDHelpers to replace backslashes with forward slashes (Maxime Rainville)
  • 2020-03-17 7ad5f1bb1 Ensure diff arrays are one-dimensional (Aaron Carlino)
  • 2020-03-08 b269d8749 Register new sub tasks to fix files affected by CVE-2020-9280 and CVE-2019-12245 (Serge Latyntcev)
  • 2020-03-05 6c25480 Rename exposed url module to node-url to avoid API clash (Garion Herman)
  • 2020-03-04 12ea7cd Create NormaliseAccessMigrationHelper to fix files affected by CVE-2019-12245 (Maxime Rainville)
  • 2020-02-27 fe14d39 Increment targeted version of recipe-cms on travis build (Maxime Rainville)
  • 2020-02-24 bba0f2f72 Fixed issue where TimeField_Readonly would only show "(not set)" instead of the value (UndefinedOffset)
  • 2020-02-21 9733060d1 Fix Related section at bottom of document (Zubair)
  • 2020-02-20 ff417ca Fix last file upload showing as errored when uploading multiple files. (bergice)
  • 2020-02-19 7455d14 Handle case where provided $context is null (Garion Herman)
  • 2020-02-19 8402966 Correct deprecated implode syntax for PHP 7.4 compat (Garion Herman)
  • 2020-02-18 9900d07 Tweak UsedOnTableTest ti dynamically switch protocol (Maxime Rainville)
  • 2020-02-18 e0de15f Fix broken test when FulltextSearchable is enabled (Maxime Rainville)
  • 2020-02-14 939cb93 Fix wording in comment in assets htaccess (aNickzz)
  • 2020-02-12 202d061 Display bulk publish button on modified files as well as draft file (Maxime Rainville)
  • 2020-02-05 c92e3b9d Prioritise same-level pages in OldPageRedirector (Klemen Dolinšek)
  • 2020-01-14 64bf56a Improve grammar in BulkDeleteMessage strings (Garion Herman)
  • 2020-01-13 e294214 Behat test should now verify that folder in use CAN be deleted (Garion Herman)
  • 2019-12-23 c8c1c86d7 module link "recaptcha" not found (Valentino Pesce)
  • 2019-12-20 1d7a0b7 Use more resilient method to manipulate URL of preview (#137) (Maxime Rainville)
  • 2019-12-19 944cf5a Upgrade webpack config to 1.4 (Maxime Rainville)
  • 2019-12-19 910f5efbf fix markdown tables for url variables documentation (Andrew Aitken-Fincham)
  • 2019-12-18 8d69cf9f7 Remove bad default when scaffolding form field for DBHTMLVarchar (Maxime Rainville)
  • 2019-12-09 1633ddea9 Fix PHP versions in upgrade guide (Matt Peel)
  • 2019-12-04 de96188c If no parent in RelativeLink() return null (Amol Wankhede)
  • 2019-11-21 f3db5f72 Fix codestyle (Serge Latyntcev)
  • 2019-11-19 e520a2b99 Fix broken callout tags (Aaron Carlino)
  • 2019-11-18 6ff0f3f46 The "Link existing" should be disabled rather than readonly. (Maxime Rainville)
  • 2019-11-18 48f9ec3 Set min-width on loading button to avoid having the loading indicator break over 2 lines (Maxime Rainville)
  • 2019-11-18 5e611341 Fixed 404s in Contributing doc (Rob Mac Neil)
  • 2019-09-02 6d8a4bc Make AbsoluteLink work with manipulated images (fixes #322) (Loz Calver)
  • 2019-03-20 1d406c64b Fix: Allow editing of relation if item is created. (Kong Jin Jie)