CVE-2026-51956 Overview
CVE-2026-51956 is a Broken Object Level Authorization (BOLA) vulnerability in Grashjs Atlas CMMS versions prior to v1.6.0. The flaw resides in the /company/{id} endpoint, which fails to validate tenant ownership before returning or updating company records. An authenticated user from one tenant can read and modify another tenant's company profile data by incrementing or substituting the numeric id parameter. The vulnerability maps to [CWE-284: Improper Access Control] and enables cross-tenant data exposure and tampering in a multi-tenant SaaS deployment.
Critical Impact
Any authenticated tenant user can view and modify company records belonging to other tenants, breaking multi-tenant isolation and enabling unauthorized data disclosure and modification.
Affected Products
- Grashjs Atlas CMMS versions prior to v1.6.0
- CompanyController component in the Atlas CMMS API
- CompanySettingsController component in the Atlas CMMS API
Discovery Timeline
- 2026-09-01 - CVE-2026-51956 published to NVD
- 2026-09-02 - Last updated in NVD database
Technical Details for CVE-2026-51956
Vulnerability Analysis
The vulnerability affects the REST endpoint /company/{id} in Grashjs Atlas CMMS. When an authenticated user issues a GET or PUT request against this endpoint, the application retrieves the Company object by primary key and returns or updates it without comparing the record's tenant identifier against the caller's tenant. The same pattern exists in the CompanySettingsController, which exposes CompanySettings records tied to other tenants' companies. In a multi-tenant deployment, every tenant shares the same numeric ID space, so an attacker can enumerate IDs and access arbitrary tenants' data. This defeats the tenant isolation model that CMMS platforms rely on for confidentiality and integrity of customer records.
Root Cause
The root cause is missing object-level authorization in the CompanyController.getById and CompanySettingsController.getById methods. The code retrieves the entity from the repository and returns it directly without checking whether entity.getCompany().getId() matches user.getCompany().getId(). Authentication is enforced, but authorization at the object level is absent.
Attack Vector
An authenticated user in tenant A sends an HTTP request such as GET /company/42 or PUT /company/42 with a target company ID belonging to tenant B. The API returns or updates the record without verifying ownership. No special privileges are required; a standard low-privilege tenant account suffices.
// Patched code from CompanyController.java
Optional<Company> companyOptional = companyService.findById(id);
if (companyOptional.isPresent()) {
Company savedCompany = companyOptional.get();
if (!savedCompany.getId().equals(user.getCompany().getId()))
throw new CustomException("Access denied", HttpStatus.FORBIDDEN);
return companyMapper.toShowDto(savedCompany);
} else throw new CustomException("Not found", HttpStatus.NOT_FOUND);
Source: GitHub Commit 283bbc9. The patch adds the tenant ownership check that was previously missing, returning HTTP 403 when the requested company does not belong to the caller.
Detection Methods for CVE-2026-51956
Indicators of Compromise
- HTTP requests to /company/{id} where {id} does not match the authenticated user's tenant company ID.
- Sequential or enumerated numeric IDs targeting the /company/ and /company-settings/ endpoints from a single session.
- Unexpected 200 OK responses to cross-tenant object reads in application access logs prior to patching.
- Modifications to company profile fields (name, address, settings) not initiated by administrators of the owning tenant.
Detection Strategies
- Parse application access logs and correlate the authenticated user's tenant ID with the {id} path parameter to flag mismatches.
- Deploy a web application firewall rule that inspects requests to /company/* and /company-settings/* endpoints for ID enumeration patterns.
- Enable database audit logging on the company and company_settings tables to identify updates performed by users outside the owning tenant.
Monitoring Recommendations
- Alert on any authenticated session that accesses more than one distinct company ID within a short interval.
- Baseline normal /company/{id} traffic per user and flag deviations that suggest ID scanning.
- Retain API access logs with full request URIs and authenticated principal identifiers for forensic review.
How to Mitigate CVE-2026-51956
Immediate Actions Required
- Upgrade Grashjs Atlas CMMS to v1.6.0 or later, which contains the tenant ownership checks in CompanyController and CompanySettingsController.
- Review application and database audit logs for cross-tenant access to company and company settings records since deployment.
- Rotate any credentials or API keys that may have been exposed through the company or company settings endpoints.
- Notify tenants whose company records were accessed or modified by unauthorized principals.
Patch Information
The fix is delivered in upstream commit 283bbc985cda497d6b592faae45ae1dbc8d53966. It adds an explicit check that compares the retrieved Company (or CompanySettings.getCompany()) ID against the authenticated user's user.getCompany().getId() and throws CustomException("Access denied", HttpStatus.FORBIDDEN) on mismatch. See the full advisory at the CVE-2026-51956 security advisory.
Workarounds
- Place an authenticating reverse proxy in front of the API that rewrites or validates the {id} path parameter against the session's tenant claim.
- Restrict the /company/{id} and /company-settings/{id} endpoints to administrator roles until the patched version is deployed.
- Apply the upstream patch as a private hotfix build if immediate upgrade to v1.6.0 is not feasible.
# Verify the running Atlas CMMS version and confirm the patched build
curl -sS https://cmms.example.com/actuator/info | jq '.build.version'
# Expected output: "1.6.0" or higher
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.