Skip to content

123 f6 cross team mcp registration#7892

Open
hardillb wants to merge 7 commits into
mainfrom
123-F6-cross-team-mcp-registration
Open

123 f6 cross team mcp registration#7892
hardillb wants to merge 7 commits into
mainfrom
123-F6-cross-team-mcp-registration

Conversation

@hardillb

Copy link
Copy Markdown
Contributor

fixes FlowFuse/security#125

see FlowFuse/security#123 for details

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.87179% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.65%. Comparing base (5802322) to head (bd2b824).
⚠️ Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
forge/ee/routes/mcp/registrations.js 94.11% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7892      +/-   ##
==========================================
+ Coverage   75.60%   75.65%   +0.05%     
==========================================
  Files         432      432              
  Lines       23046    23109      +63     
  Branches     6111     6132      +21     
==========================================
+ Hits        17424    17484      +60     
- Misses       5622     5625       +3     
Flag Coverage Δ
backend 75.65% <94.87%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread forge/ee/routes/mcp/registrations.js Outdated
Comment thread test/unit/forge/ee/routes/mcp/index_spec.js
Comment thread forge/ee/routes/mcp/registrations.js Outdated
@andypalmi

andypalmi commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Two things that are not line-specific:

  • The DELETE lookup (byTypeAndIDs) is not scoped by team, so it still matches rows across teams. With the new owner and team checks in front it should not be reachable cross-team, but scoping the lookup by request.team.id would line up with the original finding.
  • The register and delete paths do not emit an audit event, so MCP registration changes are silent. That was called out as a secondary point in the finding.

All handled in commit 4558d25

The owner check compared the URL :typeId against the token ownerId
directly. For device tokens the URL carries the hashid while ownerId is
the numeric id, so a device could never register or delete its own MCP
entry. Compare the resolved target id instead.

Also tidy the delete handler: drop the duplicated team check, guard for a
missing device or instance with a 404, return 400 for an unknown target
type, and scope the registration lookup to the resolved id and team.
The device branch resolved the target id to the numeric device id, which
Postgres rejects when compared against the varchar targetId column. Use
the string form so the lookup stays a varchar comparison.

@Steve-Mcl Steve-Mcl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this. The pre-operation code in the POST and DELETE handlers is almost identical, the only real difference being that POST throws (which gets swallowed by the try/catch and returned as a generic 500) where it should be replying with a proper status code. A "device not found" or "unknown type" is a 404/400, not a 500, so the two handlers are out of alignment on how they report the same failures.

I believe we should refactor the pre-op checks (resolve device/instance, verify team ownership, and confirm the target matches the session owner) into a common function used by both POST and DELETE. That keeps the behaviour consistent and avoids this kind of misalignment creeping in again as the code changes.

@andypalmi

Extract the device/instance resolution, team ownership, and owner
match checks into a shared function used by both routes, so unknown
device/instance/type now return 404/400 on POST instead of a generic
500 from the broad try/catch, matching what DELETE already returned.
@andypalmi

Copy link
Copy Markdown
Contributor

Agreed, refactored the pre-op checks into a shared resolveTarget function used by both POST and DELETE. It resolves the device/instance, checks team ownership, and confirms the target matches the session owner, replying with the same status code for the same failure in both routes (404 not found, 400 unknown type, 403 unauthorized). POST no longer swallows these into a generic 500. Pushed in d8940e5.

Updated the three POST tests that asserted the old 500 behavior to expect 404/404/400 to match DELETE.

@andypalmi

Copy link
Copy Markdown
Contributor

To be clear, the 500 was already there before your review, I just hadn't considered it worth changing. Agreed 400/404 is more useful for callers than a blanket 500, thanks for flagging it.

@andypalmi
andypalmi requested a review from Steve-Mcl July 22, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants