CVE-2026-85387 Overview
CVE-2026-85387 is a session management flaw in Concrete CMS versions prior to 9.5.4. The resource server validating OAuth REST API requests relied only on the presence, expiration, and explicit revocation status of the bearer token. It did not re-check the state of the account the token was issued to. Deactivating, deleting, or locking a user account did not revoke that user's outstanding tokens. A deactivated user therefore retained full access to /ccm/api/1.0/* endpoints for the remaining lifetime of any previously issued token. The vulnerability is tracked under [CWE-613: Insufficient Session Expiration]. Myq Larson reported the issue to the Concrete CMS security team.
Critical Impact
Deactivated, deleted, or password-reset-locked accounts retain full OAuth REST API access until their existing tokens naturally expire.
Affected Products
- Concrete CMS versions prior to 9.5.4
- Concrete CMS OAuth REST API endpoints (/ccm/api/1.0/*)
- Concrete CMS resource server authorization validator
Discovery Timeline
- 2026-09-16 - CVE-2026-85387 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-85387
Vulnerability Analysis
The defect resides in how Concrete CMS re-authorizes OAuth-protected REST API requests. When a client presents a bearer token to /ccm/api/1.0/*, the resource server's authorization validator performs three checks: the token exists, the token has not expired, and the token has not been explicitly revoked. The validator never queries the current state of the account associated with the token.
This omission decouples token validity from account lifecycle events. Administrative actions such as deactivating a user, deleting a user, or locking an account pending a forced password reset do not invalidate any bearer tokens the account previously received. The tokens continue to grant the original scope of API access until they reach their natural expiration.
The issue is classified under [CWE-613: Insufficient Session Expiration]. The window of exposure depends on the configured token lifetime and on whether an administrator manually revokes each outstanding token.
Root Cause
The root cause is a missing account-state check inside the OAuth resource server's authorization validator. Concrete CMS treated administrative account-state transitions and OAuth token revocation as independent operations. Deactivation, deletion, and password-reset lockouts modified account state without cascading to the token store, leaving previously issued tokens fully honored.
Attack Vector
Exploitation requires an attacker who already holds a valid OAuth bearer token issued to an account that has since been deactivated, deleted, or locked. Common scenarios include a terminated employee retaining a token issued before offboarding, or an account compromised before an administrator forced a password reset. The attacker sends authenticated requests to /ccm/api/1.0/* using the retained token. The resource server accepts the token and processes the request with the original account's permissions. No exploit code is required. The attack reduces to reusing a token the attacker legitimately received earlier. See the ConcreteCMS 9.5.4 Release Notes for the vendor description of the fix.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-85387
Indicators of Compromise
- Successful authenticated requests to /ccm/api/1.0/* originating from users whose accounts are marked deactivated, deleted, or locked in the Concrete CMS user table.
- API activity from bearer tokens whose associated user has an account-state change timestamp older than the last observed token use.
- Repeated API calls from IP addresses or user agents historically tied to offboarded personnel.
Detection Strategies
- Correlate OAuth access logs from /ccm/api/1.0/* with the Concrete CMS user account state table and flag any request whose subject user is not currently active.
- Alert on token usage that occurs after an administrative deactivation, deletion, or forced password reset event for the same user identifier.
- Baseline normal REST API usage per account and flag continued activity from accounts that appear inactive in the identity store.
Monitoring Recommendations
- Ingest Concrete CMS web server and application logs into a centralized log platform and retain OAuth token identifiers for correlation.
- Monitor administrative events such as user deactivation and password reset lockouts, then automatically enumerate active tokens for the affected user.
- Track the rate of /ccm/api/1.0/* requests per account and investigate accounts whose API traffic continues after a lifecycle change.
How to Mitigate CVE-2026-85387
Immediate Actions Required
- Upgrade Concrete CMS to version 9.5.4 or later, which introduces the account-state check inside the OAuth authorization validator.
- Manually revoke all outstanding OAuth tokens for any user account that has been deactivated, deleted, or locked pending a forced password reset.
- Audit /ccm/api/1.0/* access logs for the token lifetime window to identify requests made by inactive accounts.
Patch Information
Concrete CMS 9.5.4 remediates the vulnerability by re-checking the state of the account associated with a bearer token during OAuth request authorization. Requests presenting a token whose account is deactivated, deleted, or locked are rejected. Administrators should review the ConcreteCMS 9.5.4 Release Notes for full upgrade guidance.
Workarounds
- Reduce the configured OAuth access token lifetime so that the exposure window following an account state change is minimized.
- Build an operational procedure that revokes every outstanding token for a user as part of the deactivation, deletion, and forced password reset workflows.
- Restrict OAuth REST API access at the network layer to trusted client sources where feasible, reducing the surface available to reused tokens.
# Configuration example
# Manually revoke all OAuth tokens for a user as part of offboarding.
# Replace <user_id> with the target account identifier.
mysql -u concrete -p concrete5 -e \
"DELETE FROM OauthAccessTokens WHERE userId = <user_id>;"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

