Skip to content

fix(api): prevent cross-room data exposure via query parameter injection#39471

Open
Ram-sah19 wants to merge 2 commits intoRocketChat:developfrom
Ram-sah19:fix-cross-room-query-injection
Open

fix(api): prevent cross-room data exposure via query parameter injection#39471
Ram-sah19 wants to merge 2 commits intoRocketChat:developfrom
Ram-sah19:fix-cross-room-query-injection

Conversation

@Ram-sah19
Copy link

@Ram-sah19 Ram-sah19 commented Mar 9, 2026

Fixes #39471

Security Fix: Cross-Room Data Exposure via Query Parameter Injection

When the legacy unsafe query mode (ALLOW_UNSAFE_QUERY_AND_FIELDS_API_PARAMS=TRUE) is enabled, user-supplied query parameters can override the server-enforced room constraint (rid). Due to the spread order in query merging, an attacker could supply a custom rid and access messages from rooms they are not a member of.

Root Cause

User-provided query parameters were merged with server constraints using object spread syntax, allowing the attacker-controlled rid to override the enforced room ID.

Changes

  • Sanitized user-supplied query parameters before merging with server constraints.
  • Removed protected key rid from user query input.
  • Ensured server-enforced rid always takes precedence.

Affected Endpoints

  • /api/v1/im.messages
  • /api/v1/channels.messages
  • /api/v1/groups.messages

Security Impact

Prevents authenticated users from accessing messages and files from rooms they do not have permission to access.

Testing

Verified that requests attempting to override rid through query parameters are ignored and only authorized room messages are returned.

Summary by CodeRabbit

Bug Fixes

  • Enhanced API security by refining message query filtering in channels, groups, and direct messaging endpoints to ensure proper data access restrictions.

@Ram-sah19 Ram-sah19 requested a review from a team as a code owner March 9, 2026 13:27
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Mar 9, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Mar 9, 2026

⚠️ No Changeset found

Latest commit: b1bb7ab

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@CLAassistant
Copy link

CLAassistant commented Mar 9, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2fcca6e5-3094-470e-8667-7a0af806354c

📥 Commits

Reviewing files that changed from the base of the PR and between 4f43a85 and c092f12.

📒 Files selected for processing (3)
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/im.ts
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/im.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: In Rocket.Chat test files, the im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). It does not accept slug-like constructions such as concatenating usernames together.
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.

Applied to files:

  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.

Applied to files:

  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/api/server/v1/groups.ts
  • apps/meteor/app/api/server/v1/channels.ts
  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: In Rocket.Chat test files, the im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). It does not accept slug-like constructions such as concatenating usernames together.

Applied to files:

  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/api/server/v1/im.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/api/server/v1/im.ts
🔇 Additional comments (5)
apps/meteor/app/api/server/v1/channels.ts (2)

307-317: Correct implementation of rid sanitization for channels.messages.

The fix properly sanitizes the user-supplied query by removing rid before merging. The spread order ensures server-enforced rid takes precedence since rid: findResult._id is positioned after ...userQuery in the object literal.


1457-1460: Correct implementation of rid sanitization for channels.anonymousread.

The Object.assign pattern correctly ensures that the server-determined rid overrides any value in userQuery, matching the security fix pattern used elsewhere.

apps/meteor/app/api/server/v1/groups.ts (1)

789-799: Correct implementation of rid sanitization for groups.messages.

The sanitization pattern is consistent with channels.messages: user query is copied, rid is removed, and the server-determined rid is placed after the spread ensuring it cannot be overridden.

apps/meteor/app/api/server/v1/im.ts (2)

508-518: Correct implementation of rid sanitization for im.messages.

The fix properly removes rid from the user-supplied query before spreading. Since rid is deleted from userQuery on line 509, the server-enforced rid: room._id on line 512 remains authoritative regardless of spread order.


563-565: Correct implementation of rid sanitization for im.messages.others.

The pattern correctly ensures the server-determined rid takes precedence using Object.assign, consistent with channels.anonymousread.


Walkthrough

Three API endpoints (channels.messages, groups.messages, and im.messages) were modified to prevent user-supplied rid query parameters from overriding server-enforced room ID filters. User queries are now sanitized by removing rid before constructing the final query with server-determined room IDs.

Changes

Cohort / File(s) Summary
Query Parameter Injection Prevention
apps/meteor/app/api/server/v1/channels.ts, apps/meteor/app/api/server/v1/groups.ts, apps/meteor/app/api/server/v1/im.ts
Modified message query construction across three endpoints to sanitize user-supplied query parameters. Each endpoint now copies the incoming query, removes any rid property, and reconstructs the final query by spreading the sanitized userQuery before explicitly setting rid to the server-determined room ID. This prevents authenticated users from overriding room ID filters via query parameter injection.
Hidden Messages Filter
apps/meteor/app/api/server/v1/im.ts
Added _hidden: { $ne: true } filter to im.messages endpoint queries to explicitly exclude hidden messages from results.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main security fix: preventing cross-room data exposure via query parameter injection, which directly aligns with the changeset's core objective.
Linked Issues check ✅ Passed The code changes comprehensively address all requirements from issue #39452 by sanitizing user-supplied query parameters and ensuring server-enforced rid always takes precedence across all three vulnerable endpoints (im.ts, channels.ts, groups.ts).
Out of Scope Changes check ✅ Passed All changes are strictly scoped to fixing the cross-room data exposure vulnerability in the three affected API endpoints with no extraneous modifications or unrelated functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files


Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants