fayerman-source adds project boundary checks on folder and document mutations

fayerman-source found three places in the folder/document mutation APIs where a client-supplied folder ID was trusted without verifying it belonged to the calling project. In a multi-tenant legal document tool that's an IDOR-shaped gap.

securitymulti-tenant

The change is 28 lines in backend/src/routes/projects.ts. A new loadProjectFolder helper queries project_subfolders with both id and project_id constraints - if the folder doesn't exist within the current project it returns null and the caller gets a 404.

Three mutation paths now call it. Folder moves verify the proposed parent belongs to the current project before starting the cycle-check ancestor walk. The old walk fetched parent_folder_id with only an id filter, so a parent from a different project would cause it to traverse unscoped. Folder deletes check ownership before the cascade, and the document cleanup query gains .eq("project_id", projectId) so documents from other projects aren't affected. Document moves to a new folder verify the target folder is in scope before writing.

All three gaps share the same pattern: accepting a client-supplied ID without a project-scoped database lookup. The fix is backend-only, validated by a backend build.

So what Worth pulling if your fork has the same routes and you haven't already added project-scoping to these mutation endpoints. Low risk to adopt - the change is small, isolated to one file, and doesn't touch the API surface. Skip if your fork has already replaced these routes with something else.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from fayerman-source/mike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
7062a300 fix project folder boundary checks Eli Fayerman 2026-05-04 ↗ GitHub

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-260.md from inside the repo you want the changes in.

⬇ Download capture-thread-260.md