Skip to content
Menu
Search
Browse documentation & this page

Releases and upgrading

Security hardening — what changes for an existing site

Five defaults tightened in one release. Four are invisible; one will stop a headless front end until you opt back in.

A security pass tightened several defaults at once. Most of it you will not notice. The list below is everything that can change the behaviour of a site that upgrades, in the order you are likely to meet it.

Delivery no longer trusts supplied roles unless you say so

This one can break a working site, and it fails quietly.

The Delivery API's /_/roles/{csv} segment lets a server-side front end name the roles it evaluated for its visitor, so ACL-restricted pages can be served headlessly. It is trust, not authentication: the CMS cannot verify the claim, so a browser that discovers the segment can claim Administrator and read anything.

It is now off by default. When off, the segment is ignored and the request is treated as anonymous — so ACL-restricted pages start returning 404 to a front end that was reading them yesterday. There is no error and no warning; that is what "treated as anonymous" means.

If you have a BFF that needs it, and the Delivery API is not reachable by browsers:

{
  "Cendia": {
    "AllowSuppliedRolesOnDelivery": true
  }
}

If your Delivery API is publicly reachable, leave it off and resolve rights in your front end instead. Turning it on in that position makes every ACL on the installation advisory.

A preview signing key is now required outside Development

Cendia:PreviewSigningKey used to fall back to a well-known default. A known HMAC key lets anyone mint a preview token for any release and read unpublished content, so the fallback is gone: the host refuses to start outside Development with the key empty or set to the old cendia-dev-preview-key.

The failure is at startup, with a message naming the setting — not a 500 somebody finds later. Generate one and supply it the way you supply connection strings:

openssl rand -base64 48
Cendia__PreviewSigningKey='<the generated value>'

Development still works with no configuration at all.

Passwords must be longer

New and changed passwords now need at least 12 characters with an uppercase letter, a lowercase letter, a number and a symbol. Existing passwords keep working — Identity only applies the policy when a password is set. The setup, invite and set-password forms all state the rule now.

Accounts also lock for five minutes after five failed sign-ins, and the login form accepts ten POSTs a minute from one address.

MCP is Administrator-only

The MCP endpoint is no longer "any authenticated CMS user". Its tools call content operations directly without a per-item permission check, so an author with MCP access effectively had authority over every item in the installation. It now requires the Administrator role.

If you gave an integration a non-admin account for MCP, it needs an administrator one — or it needs not to be using MCP.

Access rights are enforced where they previously were not

Media reads (list, detail, download, thumbnail), Delivery's block and media endpoints, the preview API and the trash listing now all check read access, returning 404 rather than 403 so they do not confirm that a hidden item exists.

If a person or integration could reach something by GUID that their permissions did not cover, they will stop being able to. That is the fix, but it can look like a regression — check the ACLs before assuming a bug.

Not breaking, worth knowing

  • Responses are compressed (Brotli, gzip fallback), including static files. If something in front of the app also compresses, one of you should stop.
  • Rate limiting is on for the login form only. A global per-IP limit is available via Cendia:GlobalRateLimitPerIp and is off by default, because behind a BFF every visitor shares one address and an IP limit would throttle the whole site.
  • The CMS auth cookie is HttpOnly, Secure and SameSite=Lax, and expires after 8 hours idle. Authors on a long edit stay signed in; authors who leave overnight do not.

Give an older site an error page and HSTS

Sites made from the Starter since 1.1.2 have both. Program.cs is yours, so an update to the packages cannot add them to a site made earlier: add them yourself. Without them a failed request outside Development shows a bare 500, and browsers are never told to stay on HTTPS.

app.MigrateCendiaInDevelopment();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

Then add Pages/Error.cshtml with its page model. Copy the Starter's from a new dotnet new cendia-starter: it uses no layout, because the site layout reads the database, and an error page that needs the database fails again when the database is what failed. It shows a reference number and nothing about the exception; the details are in the server log.

HSTS is sent for 30 days by default, and never for localhost. Raise it with builder.Services.AddHsts(o => o.MaxAge = TimeSpan.FromDays(365)) once you are sure every address the site answers on has a certificate: a browser that has seen the header refuses plain HTTP for that host until it expires.

Create the first administrator before the site is public

Not a change, but the one step of a self-hosted deploy that cannot wait.

On a self-hosted site with no accounts yet, /cms/setup asks for nothing: whoever reaches it first creates the first administrator. That is deliberate, because the person installing the site is normally the one who gets there. It also means a site deployed to a public address with an empty database can be claimed by a stranger who finds it first.

So create the administrator before the address is reachable from outside: against the production database from your own machine, behind an IP restriction or private endpoint while you deploy, or on a slot nobody else knows. Once one account exists the page only redirects to the CMS.

Sites on Cendia hosting are not exposed this way: there the page asks for the one-time code in the setup link the platform issues.