Code reading on 28 September 2026 at b5727e0. Unverified: not checked live, and the effect below is read from code only.
What happens
SecretService::create() copies folderId from the request onto the new secret without checking that the folder belongs to the caller (lib/Service/SecretService.php:266):
$secret->setFolderId($this->nullableString(value: $data['folderId'] ?? null));
SecretController::create() (lib/Controller/SecretController.php:269) adds no folder check either. update() does the same on a move (SecretService.php:849), and so do createForApplication() (:355), createByApplication() (:457) and updateByApplication() (:545).
What a foreign folderId does, as far as the code shows:
- The folder owner's delete counts the folder's secrets with no owner filter (
lib/Service/FolderDeletionService.php:106, :129, through SecretMapper::countByFolder()). An otherwise empty folder with a planted secret then asks for a cascade plan instead of deleting.
SecretChildDataCleaner::purgeForFolder() finds the folder's secrets with no owner filter either (lib/Service/SecretChildDataCleaner.php:101).
The lane that found this saw no effect on team folder fan-out. Folder ids are UUIDs, so this needs a known id.
Live check
As user B, POST a secret carrying user A's folder id, then as user A delete that otherwise empty folder, and confirm whether the delete is refused or B's secret is touched.
Found by the OpenSpec pass (keepiq#769).
Code reading on 28 September 2026 at b5727e0. Unverified: not checked live, and the effect below is read from code only.
What happens
SecretService::create()copiesfolderIdfrom the request onto the new secret without checking that the folder belongs to the caller (lib/Service/SecretService.php:266):SecretController::create()(lib/Controller/SecretController.php:269) adds no folder check either.update()does the same on a move (SecretService.php:849), and so docreateForApplication()(:355),createByApplication()(:457) andupdateByApplication()(:545).What a foreign
folderIddoes, as far as the code shows:lib/Service/FolderDeletionService.php:106,:129, throughSecretMapper::countByFolder()). An otherwise empty folder with a planted secret then asks for a cascade plan instead of deleting.SecretChildDataCleaner::purgeForFolder()finds the folder's secrets with no owner filter either (lib/Service/SecretChildDataCleaner.php:101).The lane that found this saw no effect on team folder fan-out. Folder ids are UUIDs, so this needs a known id.
Live check
As user B, POST a secret carrying user A's folder id, then as user A delete that otherwise empty folder, and confirm whether the delete is refused or B's secret is touched.
Found by the OpenSpec pass (keepiq#769).