From 92a6905a8dda9252ebeef890d2f840038587367e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 16 Jul 2026 09:33:27 -0300 Subject: [PATCH] refactor(authorization): forward only { _id, roles } from hasPermission wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `hasPermissionAsync` / `hasAllPermissionAsync` / `hasAtLeastOnePermissionAsync` helpers accept a full user object but only `_id` and `roles` are ever used by the check. Passing the whole document means credential-bearing fields (`services`, `e2e.private_key`, …) get serialized to the authorization service when it runs out of process. Normalize object inputs to a minimal `{ _id, roles }` subject before the call; string ids pass through unchanged. --- apps/meteor/server/lib/authorization/hasPermission.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/meteor/server/lib/authorization/hasPermission.ts b/apps/meteor/server/lib/authorization/hasPermission.ts index aef811ef3a6fd..2cf2fa5cb6412 100644 --- a/apps/meteor/server/lib/authorization/hasPermission.ts +++ b/apps/meteor/server/lib/authorization/hasPermission.ts @@ -2,18 +2,23 @@ import { Authorization } from '@rocket.chat/core-services'; import type { UserWithRoles } from '@rocket.chat/core-services'; import type { IUser, IPermission, IRoom } from '@rocket.chat/core-typings'; +// Forward only the fields the permission check needs, so a full user document +// (with services, e2e keys, etc.) isn't serialized to the authorization service. +const toSubject = (user: IUser['_id'] | UserWithRoles): IUser['_id'] | UserWithRoles => + typeof user === 'string' ? user : { _id: user._id, roles: user.roles }; + export const hasAllPermissionAsync = async ( user: IUser['_id'] | UserWithRoles, permissions: IPermission['_id'][], scope?: IRoom['_id'], -): Promise => Authorization.hasAllPermission(user, permissions, scope); +): Promise => Authorization.hasAllPermission(toSubject(user), permissions, scope); export const hasPermissionAsync = async ( user: IUser['_id'] | UserWithRoles, permissionId: IPermission['_id'], scope?: IRoom['_id'], -): Promise => Authorization.hasPermission(user, permissionId, scope); +): Promise => Authorization.hasPermission(toSubject(user), permissionId, scope); export const hasAtLeastOnePermissionAsync = async ( user: IUser['_id'] | UserWithRoles, permissions: IPermission['_id'][], scope?: IRoom['_id'], -): Promise => Authorization.hasAtLeastOnePermission(user, permissions, scope); +): Promise => Authorization.hasAtLeastOnePermission(toSubject(user), permissions, scope);