You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
1. TOCTOU race: appSlugExists checks for an existing slug, then saveObject creates the new Application. Two parallel createApp calls with the same slug both pass the check before either writes, both call saveObject, and two Applications end up with the same slug. getAppManifest and BuiltAppRoute index then resolve arbitrarily between the two.
2. Cross-organisation leak via mismatched multitenancy flags: appSlugExists uses _multitenancy: false for its register/schema lookup, but the subsequent searchObjects does not explicitly pin tenancy, and saveObject uses the default _multitenancy: true. A slug taken in org-B may therefore appear free to org-A depending on the caller's tenancy context, producing cross-org slug collisions that getAppManifest later resolves with _multitenancy: false (wrong result).
Suggested fix:
Add a DB unique constraint on (register, schema, slug), OR use lockObject($slugLockKey) around the check-then-create pair.
Align all multitenancy flags in appSlugExists, searchObjects, and saveObject to a single consistent value; document the chosen semantics.
Severity: MEDIUM
Location:
lib/Service/ApplicationCreationService.php:504, 565-595(appSlugExists)Description:
Two problems with slug uniqueness:
1. TOCTOU race:
appSlugExistschecks for an existing slug, thensaveObjectcreates the new Application. Two parallelcreateAppcalls with the same slug both pass the check before either writes, both callsaveObject, and two Applications end up with the same slug.getAppManifestandBuiltAppRouteindex then resolve arbitrarily between the two.2. Cross-organisation leak via mismatched multitenancy flags:
appSlugExistsuses_multitenancy: falsefor its register/schema lookup, but the subsequentsearchObjectsdoes not explicitly pin tenancy, andsaveObjectuses the default_multitenancy: true. A slug taken in org-B may therefore appear free to org-A depending on the caller's tenancy context, producing cross-org slug collisions thatgetAppManifestlater resolves with_multitenancy: false(wrong result).Suggested fix:
(register, schema, slug), OR uselockObject($slugLockKey)around the check-then-create pair.appSlugExists,searchObjects, andsaveObjectto a single consistent value; document the chosen semantics.Source: deep team-reviewer pass 2026-05-27