From 6ee21a39bb4204a883167a4431c197b1b89b48cf Mon Sep 17 00:00:00 2001 From: FlyeraX <79267723+jonasflorencio@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:48:31 -0300 Subject: [PATCH 1/2] fix: security hotfix --------- Co-authored-by: jonasflorencio Co-authored-by: Kevin Aleman --- .changeset/olive-queens-protect.md | 5 ++ apps/meteor/server/publications/room/index.ts | 14 ++++-- apps/meteor/tests/end-to-end/api/methods.ts | 48 +++++++++++++++++-- 3 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 .changeset/olive-queens-protect.md diff --git a/.changeset/olive-queens-protect.md b/.changeset/olive-queens-protect.md new file mode 100644 index 0000000000000..54251bde0b9f7 --- /dev/null +++ b/.changeset/olive-queens-protect.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +fix: Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/server/publications/room/index.ts b/apps/meteor/server/publications/room/index.ts index dcb9c741f2376..5a457daa937e3 100644 --- a/apps/meteor/server/publications/room/index.ts +++ b/apps/meteor/server/publications/room/index.ts @@ -58,11 +58,15 @@ Meteor.methods({ } const userId = Meteor.userId(); - - if (!userId && settings.get('Accounts_AllowAnonymousRead') === false) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'getRoomByTypeAndName', - }); + const isAnonymous = !userId; + + if (isAnonymous) { + const allowAnon = settings.get('Accounts_AllowAnonymousRead'); + if (!allowAnon || type !== 'c') { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'getRoomByTypeAndName', + }); + } } const roomFind = roomCoordinator.getRoomFind(type); diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 0d6651f74ba9b..6d9ba77737734 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -2575,6 +2575,8 @@ describe('Meteor.methods', () => { let testUserCredentials: Credentials; let dmId: IRoom['_id']; let room: IRoom; + let privateRoom: IRoom; + before(async () => { testUser = await createUser(); @@ -2613,14 +2615,52 @@ describe('Meteor.methods', () => { }); }); - after(() => - Promise.all([ + before(async () => { + privateRoom = ( + await createRoom({ + type: 'p', + name: `private.test.${Date.now()}-${Math.random()}`, + }) + ).body.group; + }); + + after(async () => { + await Promise.all([ deleteRoom({ type: 'd', roomId: dmId }), deleteRoom({ type: 'c', roomId: room._id }), + deleteRoom({ type: 'p', roomId: privateRoom._id }), deleteUser(testUser), deleteUser(testUser2), - ]), - ); + updateSetting('Accounts_AllowAnonymousRead', false), + ]); + }); + + it('should throw error when anonymous user tries to read private channel with anonymous read enabled', async () => { + await updateSetting('Accounts_AllowAnonymousRead', true); + + const payload = { + message: JSON.stringify({ + msg: 'method', + id: '2', + method: 'getRoomByTypeAndName', + params: ['p', privateRoom.name], + }), + }; + + const res = await request + .post('/api/v1/method.callAnon/getRoomByTypeAndName') + .set('Content-Type', 'application/json') + .send(payload); + + expect(res.body).to.have.property('message'); + const parsedMessage = JSON.parse(res.body.message); + + expect(parsedMessage).to.have.property('error'); + expect(parsedMessage.error).to.have.property('error'); + expect(parsedMessage.error.error).to.equal('error-invalid-user'); + + await updateSetting('Accounts_AllowAnonymousRead', false); + }); it("should throw an error if the user isn't logged in", (done) => { void request From d6573019991687e5e6d191d110f7d718eb71fc2b Mon Sep 17 00:00:00 2001 From: jonasflorencio Date: Mon, 16 Jun 2025 13:57:38 -0300 Subject: [PATCH 2/2] update lint --- apps/meteor/tests/end-to-end/api/methods.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 6d9ba77737734..6630be90104f7 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -2577,7 +2577,6 @@ describe('Meteor.methods', () => { let room: IRoom; let privateRoom: IRoom; - before(async () => { testUser = await createUser(); testUser2 = await createUser(); @@ -2647,10 +2646,7 @@ describe('Meteor.methods', () => { }), }; - const res = await request - .post('/api/v1/method.callAnon/getRoomByTypeAndName') - .set('Content-Type', 'application/json') - .send(payload); + const res = await request.post('/api/v1/method.callAnon/getRoomByTypeAndName').set('Content-Type', 'application/json').send(payload); expect(res.body).to.have.property('message'); const parsedMessage = JSON.parse(res.body.message);