fix: CRITICAL — scope copilot tree query to current account #131

Merged
chihlasm merged 4 commits from fix/copilot-tree-access-bypass into main 2026-04-09 04:41:30 +00:00
chihlasm commented 2026-04-09 04:22:49 +00:00 (Migrated from github.com)

Summary

  • CRITICAL security fix: start_conversation() in copilot_service.py loaded a tree by UUID with no account filter — an attacker knowing another account's tree UUID could extract its full node structure, names, and descriptions via the AI system prompt
  • Fix: scope the tree SELECT to account_id == current_account OR is_default OR is_public OR author_id == user
  • Returns 404 for inaccessible trees (never 403 — never confirm existence)
  • Test added: test_copilot_cannot_start_conversation_with_other_account_tree

Impact

Any authenticated user with a known tree UUID from another account could start a copilot conversation and have that tree's content injected into the AI system prompt. Full cross-tenant data disclosure via the AI layer.

Test plan

  • CI passes — test_copilot_cannot_start_conversation_with_other_account_tree confirms Account A gets 404 on Account B's private tree
  • Verify copilot conversations still work normally for own-account trees
  • Verify default/public trees remain accessible to all accounts
  • Merge this PR before feat/tenant-isolation-phase-0

🤖 Generated with Claude Code

## Summary - **CRITICAL security fix**: `start_conversation()` in `copilot_service.py` loaded a tree by UUID with no account filter — an attacker knowing another account's tree UUID could extract its full node structure, names, and descriptions via the AI system prompt - Fix: scope the tree SELECT to `account_id == current_account OR is_default OR is_public OR author_id == user` - Returns 404 for inaccessible trees (never 403 — never confirm existence) - Test added: `test_copilot_cannot_start_conversation_with_other_account_tree` ## Impact Any authenticated user with a known tree UUID from another account could start a copilot conversation and have that tree's content injected into the AI system prompt. Full cross-tenant data disclosure via the AI layer. ## Test plan - [ ] CI passes — `test_copilot_cannot_start_conversation_with_other_account_tree` confirms Account A gets 404 on Account B's private tree - [ ] Verify copilot conversations still work normally for own-account trees - [ ] Verify default/public trees remain accessible to all accounts - [ ] **Merge this PR before `feat/tenant-isolation-phase-0`** 🤖 Generated with [Claude Code](https://claude.com/claude-code)
railway-app[bot] commented 2026-04-09 04:23:05 +00:00 (Migrated from github.com)

🚅 Deployed to the resolutionflow-pr-131 environment in selfless-grace

Service Status Web Updated (UTC)
patherly Success (View Logs) Apr 9, 2026 at 4:23 am
hopeful-liberation Success (View Logs) Apr 9, 2026 at 4:23 am
<!-- railway-bot-comment-version=2 --> <!-- railway-project-id="22b9b58c-271b-42e5-a10e-6fdec8d00134" railway-project-name="selfless-grace" --> 🚅 Deployed to the [resolutionflow-pr-131](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134?environmentId=610ab172-a55f-4bf8-9513-f7831c12eafd) environment in **[selfless-grace](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134)** | **Service** | **Status** | **Web** | **Updated** (UTC) | | :--- | :--- | :--- | :--- | | patherly | ✅ Success ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/95f556ff-5264-4116-a0c2-618a2fc53ba4?id=d0a9cd17-d687-45ae-a008-c589d33b0d96&environmentId=610ab172-a55f-4bf8-9513-f7831c12eafd)) | | Apr 9, 2026 at 4:23 am | | hopeful-liberation | ✅ Success ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/e1db2ee3-d241-4f45-abe4-c9c5fdf483d5?id=740910a1-aa38-4ade-b0bd-fd39aafa0aed&environmentId=610ab172-a55f-4bf8-9513-f7831c12eafd)) | | Apr 9, 2026 at 4:23 am |
Sign in to join this conversation.