CVE case study
CVE-2026-59979: Missing Tenant Checks in Yosemite-Crew Routes
Several read, update, and delete routes either lacked authentication or stopped at identity checks before globally keyed lookups.
- Weakness
- CWE-639 · CWE-862
- Affected
- Main branch through bc1a1824b1a7eba2bc61176cdb61d9a2a11bce57
- Remediation state
- No complete fixed release is listed by the advisory
- Advisory published
- 21 Jun 2026
Official vectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H
Why it matters
Affected routes either skipped authentication or checked identity without checking organization membership and operation permission.
The service queried records by global ID, so a caller with another tenant's ID could reach that record.
How I found it
I compared middleware across create, read, update, and delete routes in the same Yosemite-Crew router.
The create routes carried authentication, withOrgPermissions(), and requirePermission(). The update and delete routes carried only authorizeCognito, while the single-service read route had no authentication middleware. I opened authorizeCognito to avoid assuming its name implied authorization; it verified the token and set userId, but performed no organization or role lookup.
I followed :id through the controller. No tenant identity reached the service, which used a global findById(). The PMS task-library and template routes had the same gap, showing an incomplete authorization update across the route family.
Root cause
Affected routes omitted tenant and permission middleware, and the service queried by ID without organisationId.
Source-to-sink trace
- 01Intent control
service.router.ts · create routesSibling operations use authentication, organization membership, and an explicit permission requirement.
- 02Missing route guard
service.router.ts · GET/PATCH/DELETE /:idRead has no guard; update and delete use authentication only.
- 03Identity-only middleware
middlewares/auth.ts · authorizeCognitoThe middleware establishes user identity but not tenant membership or function permission.
- 04Unscoped data sink
service.service.ts · findById()The controller supplies only a global object ID, and the service lookup does not filter by
organisationId.
Safe proof of concept
Prerequisites
- Git and
rginstalled locally. - A clone of the public Yosemite-Crew repository; no account, token, database, or hosted target is needed.
Step-by-step reproduction
- Clone the public repository and check out
bc1a1824b1a7eba2bc61176cdb61d9a2a11bce57, the revision named by the advisory. - Run the assertions below. They verify the full RBAC stack on sibling create routes, authentication-only update/delete routes, and the unguarded read route.
- Open
authorizeCognitoand confirm that it establishesuserIdbut performs no organization or permission lookup. - Trace
updateServicefrom router to controller to service. Confirm that only:idand the DTO reach a globalfindById()query. - Repeat the same check for task-library and template routes.
- If you build an optional runtime lab, seed two synthetic organizations through the project’s supported fixtures, obtain a valid local token, fetch a complete valid
ServiceRequestDTO, change one benign field, and PATCH that full DTO. Do not use a one-field body or a production record.
Clone the audited revision
git clone https://github.com/YosemiteCrew/Yosemite-Crew.git yosemite-cve-lab
cd yosemite-cve-lab
git checkout bc1a1824b1a7eba2bc61176cdb61d9a2a11bce57Offline authorization assertions
SERVICE_ROUTER=apps/backend/src/routers/service.router.ts
AUTH=apps/backend/src/middlewares/auth.ts
SERVICE=apps/backend/src/services/service.service.ts
TASK_ROUTER=apps/backend/src/routers/task.router.ts
# Intent control: sibling create routes have organization + permission guards.
rg -n 'withOrgPermissions|requirePermission\("specialities:edit:any"\)' "$SERVICE_ROUTER"
# Gap: read is unguarded; update/delete are authentication-only.
rg -n 'router\.(get|patch|delete)\("/:id"' "$SERVICE_ROUTER"
# Authentication establishes identity, not tenant or role authorization.
rg -n 'authorizeCognito|authReq.userId = payload.sub' "$AUTH"
# Controller/service path reaches a global lookup with no tenant key.
rg -n 'updateService|findById\(oid\)|organisationId' "$SERVICE"
# Same census for the task library/template family.
rg -n 'pms/library|pms/templates|withTaskOrgPermissions|requirePermission' "$TASK_ROUTER"Expected evidence
- The output shows the complete authorization stack on sibling create/task operations and its absence from the disclosed read/update/delete family.
- The authentication middleware sets caller identity without loading organization membership or permissions.
- The update path reaches
findById()without anorganisationIdpredicate; the proof contacts no application endpoint and changes no data.
The guarded create routes show the expected stack: authentication, organization membership, and explicit permission checks.
The vendor advisory still lists no complete fixed release. A candidate fix must add authentication, organization membership, permission enforcement, and organisationId-scoped queries across every named route family. Only then should an owned two-tenant integration test assert 401, 403, or a non-enumerating 404 and an unchanged synthetic record.
Impact
The advisory documents cross-tenant disclosure, modification, and deletion of service-catalogue and PMS task-definition data. Integrity and availability impact are high because state-changing operations can affect downstream workflows such as bookings and billing.
Most affected write paths require only a low-privilege account and a target identifier. The disclosed service-by-ID read path was reachable without authentication, further demonstrating why every object operation needs its own policy check.
Fix and retest
Apply authentication, organization membership, and explicit permission middleware to every affected route. Backend methods should also accept the tenant identity and query by both object ID and organisationId, so a missed route guard fails closed.
As of this review, the vendor advisory lists no fixed release. Public source shows partial hardening of service update and delete paths, but it does not justify claiming the entire disclosed route family is fixed. Deployment owners should compare their version with the vendor advisory and verify every named operation.
Engineering lesson
Test create, list, read, update, delete, archive, and template routes against the same authorization matrix.