DEV Community

kozhevniko
kozhevniko

Posted on

A Deactivated User With a Live Token: Reading Concrete CMS CVE-2026-85387 as a Revocation Gap

A Deactivated User With a Live Token: Reading Concrete CMS CVE-2026-85387 as a Revocation Gap

Revocation is the part of identity that nobody tests

Identity work concentrates on issuing credentials and verifying them. Revoking them is treated as an administrative outcome rather than a security control. CVE-2026-85387 in Concrete CMS is a useful case because the defect sits entirely inside that neglected half of the lifecycle.

What the advisory describes

Concrete CMS before 9.5.4 re-authorized OAuth REST API requests from the bearer token alone. The resource server's authorization validator confirmed that a token existed, had not expired and had not been explicitly revoked. It did not re-check the state of the account the token had been issued to.

Deactivating a user did not revoke that user's outstanding tokens. A deactivated user therefore retained full access to /ccm/api/1.0/* for the remaining lifetime of any token already issued to them. The same gap applied to accounts that had been deleted, and to accounts locked pending a forced password reset.

The project assigned the issue a CVSS 4.0 score of 2.0 with the vector CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:A/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N. Read the vector rather than the score. The attack requires a position (AT:P), a low-privilege authenticated actor (PR:L) and user interaction (UI:A), and the impact is confined to confidentiality and integrity within the vulnerable system.

Why the low score needs context

The score measures the vulnerability, not the deployment. In an estate where the CMS holds marketing content, the impact of a deactivated account retaining API access is small. In an estate where the same installation is the system of record for customer-facing pages, integrations and documents, the gap is a live dormant credential that ordinary offboarding is supposed to eliminate.

The related issues in the same release window make the picture clearer. CVE-2026-81901 covers the REST API page update endpoint failing to enforce page-property, page-template and page-type authorization, which allowed a user with content-editing rights to set an attribute rendered unescaped into the head of every page; NVD scores it 8.7. CVE-2026-85385 is a stored cross-site scripting flaw in the user timezone field, reachable by any authenticated user in versions below 9.5.3, and by unauthenticated visitors through public registration in 9.5.3 when the concrete.misc.user_timezones flag is enabled.

Taken together, these three advisories describe an application whose authorization model was checked at the token layer and not always at the object layer.

Defensive implications

Update to Concrete CMS 9.5.4 or later. This release covers all three issues described here.

Then test the behaviour directly rather than assuming it. Issue a token to a test account, deactivate the account, and call an API endpoint with the retained token. The result tells you whether your deployment relies on a control that the application itself did not enforce before 9.5.4.

Change offboarding so that deactivation is not the last step. An identity process that deactivates an account should also revoke its tokens and sessions, which in turn requires knowing where those tokens live. Where the CMS issues tokens to integrations, keep a register of which integration holds which credential so that revocation can be performed when the integration is retired.

Finally, shorten token lifetimes for administrative and integration accounts. A one-hour token that survives deactivation for an hour is a bounded problem; a thirty-day token is a thirty-day problem, and the score assigned to the vulnerability does not change the arithmetic.

References

  • NVD records for CVE-2026-85387, CVE-2026-81901 and CVE-2026-85385.

Top comments (0)