Skip to content

Creating or moving a secret accepts a folder the user does not own #795

Description

@rubenvdlinde

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsecurityA user can read or write what they must nottriageAwaiting triage

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions