FileNode/set create does not check AddItems on the parent: a read-only sharee can create nodes anywhere in the owner's tree

Issue Description

When account A shares a FileNode folder with account B at read level only (mayRead), B can create new nodes anywhere in A’s FileNode tree via JMAP FileNode/set create, including under folders A has not shared with B at all. FileNode/set create does not check that the acting principal holds AddItems (mayAddChildren) on the target parent.

Measured on v0.16.20. crates/jmap/src/file/set.rs is byte-identical in v0.16.27, so the current release should behave the same (not re-measured there).

Expected Behavior

Creating a child node in a shared account requires AddItems (mayAddChildren) on the parent node, mirroring the Modify/Delete checks that update and destroy already perform. Without it, the create is rejected with forbidden.

Actual Behavior

Any recipient of a read-only folder share can create nodes in every folder of the owner’s tree, including folders that were never shared with them.

Reproduction Steps

  1. Account A creates two top-level folders X and Y.
  2. A shares X with account B granting only mayRead (shareWith: {<B>: {mayRead: true}}).
  3. As B, call FileNode/set on A’s accountId with one create of an empty folder node (no blobId) whose parentId is X. → created, although B only holds mayRead on X.
  4. As B, repeat with parentId = Y (never shared with B). → created, although B has no grant on Y.
  5. Control: grant B mayAddChildren on X and repeat step 3 → created (expected).

Every created node was removed again by A right after the measurement.

Relevant Log Output

None: the requests succeed, so nothing is logged as an error.

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

FoundationDB

Blob Storage

S3-compatible

Search Engine

Internal

Directory Backend

Internal

Additional Context

Where in the code (v0.16.20 / v0.16.27)

  • validate_file_node_hierarchy (crates/jmap/src/file/set.rs:861-870) only rejects top-level nodes (parent_id == 0) in a shared account. For other parents it checks that the parent exists and is a container, not the caller’s rights on it.
  • The parent handling on create (set.rs:245-269) copies the parent’s ACL onto the new node and requires Acl::Share only when the request itself sets shareWith. A create without shareWith passes with no per-parent permission check.

Scope check: if B has no FileNode share from A (only a shared calendar or a shared mailbox), FileNode/get and FileNode/set create on A’s account correctly return forbidden (“You do not have access to account …”). So the gap needs at least one FileNode share between the two accounts.

Deployment: Docker image on Kubernetes, two replicas.

Related: the quota side of FileNode/set is already reported in “FileNode ignores disk quota”.

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

This is a detailed, well-documented bug report with specific code references rather than a question, so there isn’t a documentation answer to give here. A human maintainer will need to review the FileNode/set permission logic in crates/jmap/src/file/set.rs to confirm and fix the missing AddItems/mayAddChildren check on create.

This isn’t covered in the current docs. A community member or staff member will follow up.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.