diff --git a/.changeset/bump-patch-1723645120544.md b/.changeset/bump-patch-1723645120544.md
new file mode 100644
index 0000000000000000000000000000000000000000..e1eaa7980afb1bf8e2912d275cc61cb5b6326686
--- /dev/null
+++ b/.changeset/bump-patch-1723645120544.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': patch
+---
+
+Bump @rocket.chat/meteor version.
diff --git a/.changeset/perfect-dancers-grab.md b/.changeset/perfect-dancers-grab.md
new file mode 100644
index 0000000000000000000000000000000000000000..eacb88108a0f7fe974c6fdbea679e4472fe72a82
--- /dev/null
+++ b/.changeset/perfect-dancers-grab.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': patch
+---
+
+Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates)
diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts
index e3296b98ef17847682806892ea1851f0a0f5d19d..ee76dcdd9fe3ad88c606ede275d705bb29a3561f 100644
--- a/apps/meteor/app/api/server/v1/rooms.ts
+++ b/apps/meteor/app/api/server/v1/rooms.ts
@@ -2,7 +2,13 @@ import { Media } from '@rocket.chat/core-services';
 import type { IRoom, IUpload } from '@rocket.chat/core-typings';
 import { Messages, Rooms, Users, Uploads } from '@rocket.chat/models';
 import type { Notifications } from '@rocket.chat/rest-typings';
-import { isGETRoomsNameExists, isRoomsImagesProps, isRoomsMuteUnmuteUserProps, isRoomsExportProps } from '@rocket.chat/rest-typings';
+import {
+	isGETRoomsNameExists,
+	isRoomsCleanHistoryProps,
+	isRoomsImagesProps,
+	isRoomsMuteUnmuteUserProps,
+	isRoomsExportProps,
+} from '@rocket.chat/rest-typings';
 import { Meteor } from 'meteor/meteor';
 
 import { isTruthy } from '../../../../lib/isTruthy';
@@ -355,7 +361,7 @@ API.v1.addRoute(
 
 API.v1.addRoute(
 	'rooms.cleanHistory',
-	{ authRequired: true },
+	{ authRequired: true, validateParams: isRoomsCleanHistoryProps },
 	{
 		async post() {
 			const { _id } = await findRoomByIdOrName({ params: this.bodyParams });
diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts
index 7ae585b89dfa77e39ce8dd5ac7d58246857f161e..6c680b6648d8ad8f9b0ceeaf477e11cbabf5b02d 100644
--- a/apps/meteor/app/api/server/v1/users.ts
+++ b/apps/meteor/app/api/server/v1/users.ts
@@ -750,6 +750,12 @@ API.v1.addRoute(
 	{ authRequired: false },
 	{
 		async post() {
+			const isPasswordResetEnabled = settings.get('Accounts_PasswordReset');
+
+			if (!isPasswordResetEnabled) {
+				return API.v1.failure('Password reset is not enabled');
+			}
+
 			const { email } = this.bodyParams;
 			if (!email) {
 				return API.v1.failure("The 'email' param is required");
diff --git a/apps/meteor/app/livechat/imports/server/rest/sms.ts b/apps/meteor/app/livechat/imports/server/rest/sms.ts
index 6f8ce64bc6352548af73cea9f01a03176907fa9c..6b2411cf8e3dd8c8e49bac634017909184532bf9 100644
--- a/apps/meteor/app/livechat/imports/server/rest/sms.ts
+++ b/apps/meteor/app/livechat/imports/server/rest/sms.ts
@@ -97,12 +97,18 @@ const normalizeLocationSharing = (payload: ServiceData) => {
 // @ts-expect-error - this is an special endpoint that requires the return to not be wrapped as regular returns
 API.v1.addRoute('livechat/sms-incoming/:service', {
 	async post() {
-		if (!(await OmnichannelIntegration.isConfiguredSmsService(this.urlParams.service))) {
+		const { service } = this.urlParams;
+		if (!(await OmnichannelIntegration.isConfiguredSmsService(service))) {
 			return API.v1.failure('Invalid service');
 		}
 
 		const smsDepartment = settings.get<string>('SMS_Default_Omnichannel_Department');
-		const SMSService = await OmnichannelIntegration.getSmsService(this.urlParams.service);
+		const SMSService = await OmnichannelIntegration.getSmsService(service);
+
+		if (!SMSService.validateRequest(this.request)) {
+			return API.v1.failure('Invalid request');
+		}
+
 		const sms = SMSService.parse(this.bodyParams);
 		const { department } = this.queryParams;
 		let targetDepartment = await defineDepartment(department || smsDepartment);
@@ -121,7 +127,7 @@ API.v1.addRoute('livechat/sms-incoming/:service', {
 			},
 			source: {
 				type: OmnichannelSourceType.SMS,
-				alias: this.urlParams.service,
+				alias: service,
 			},
 		};
 
diff --git a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts
index 337691bfbe57a08239672c03fa0900d50a5f2594..640aa517a6799dde17d9d6c3f98c5d6e0b8e71a4 100644
--- a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts
+++ b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts
@@ -6,13 +6,20 @@ import { getCronAdvancedTimerFromPrecisionSetting } from '../../../lib/getCronAd
 import { cleanRoomHistory } from '../../lib/server/functions/cleanRoomHistory';
 import { settings } from '../../settings/server';
 
-const maxTimes = {
-	c: 0,
-	p: 0,
-	d: 0,
+type RetentionRoomTypes = 'c' | 'p' | 'd';
+
+const getMaxAgeSettingIdByRoomType = (type: RetentionRoomTypes) => {
+	switch (type) {
+		case 'c':
+			return settings.get<number>('RetentionPolicy_TTL_Channels');
+		case 'p':
+			return settings.get<number>('RetentionPolicy_TTL_Groups');
+		case 'd':
+			return settings.get<number>('RetentionPolicy_TTL_DMs');
+	}
 };
 
-let types: (keyof typeof maxTimes)[] = [];
+let types: RetentionRoomTypes[] = [];
 
 const oldest = new Date('0001-01-01T00:00:00Z');
 
@@ -29,7 +36,7 @@ async function job(): Promise<void> {
 
 	// get all rooms with default values
 	for await (const type of types) {
-		const maxAge = maxTimes[type] || 0;
+		const maxAge = getMaxAgeSettingIdByRoomType(type) || 0;
 		const latest = new Date(now.getTime() - maxAge);
 
 		const rooms = await Rooms.find(
@@ -95,9 +102,6 @@ settings.watchMultiple(
 		'RetentionPolicy_AppliesToChannels',
 		'RetentionPolicy_AppliesToGroups',
 		'RetentionPolicy_AppliesToDMs',
-		'RetentionPolicy_TTL_Channels',
-		'RetentionPolicy_TTL_Groups',
-		'RetentionPolicy_TTL_DMs',
 		'RetentionPolicy_Advanced_Precision',
 		'RetentionPolicy_Advanced_Precision_Cron',
 		'RetentionPolicy_Precision',
@@ -120,10 +124,6 @@ settings.watchMultiple(
 			types.push('d');
 		}
 
-		maxTimes.c = settings.get<number>('RetentionPolicy_TTL_Channels');
-		maxTimes.p = settings.get<number>('RetentionPolicy_TTL_Groups');
-		maxTimes.d = settings.get<number>('RetentionPolicy_TTL_DMs');
-
 		const precision =
 			(settings.get<boolean>('RetentionPolicy_Advanced_Precision') && settings.get<string>('RetentionPolicy_Advanced_Precision_Cron')) ||
 			getCronAdvancedTimerFromPrecisionSetting(settings.get('RetentionPolicy_Precision'));
diff --git a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx
index 19bef201492f200459d1d966acc8019202a6283a..79d2fbe11140392dababc5ab6ab1ec4815f7be6f 100644
--- a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx
+++ b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx
@@ -8,6 +8,7 @@ import {
 	FieldRow,
 	FieldError,
 	FieldHint,
+	PasswordInput,
 	TextAreaInput,
 	ToggleSwitch,
 	FieldGroup,
@@ -136,7 +137,7 @@ const EditOauthApp = ({ onChange, data, ...props }: EditOauthAppProps): ReactEle
 				<Field>
 					<FieldLabel>{t('Client_Secret')}</FieldLabel>
 					<FieldRow>
-						<TextInput value={data.clientSecret} />
+						<PasswordInput value={data.clientSecret} />
 					</FieldRow>
 				</Field>
 				<Field>
diff --git a/apps/meteor/ee/server/lib/audit/methods.ts b/apps/meteor/ee/server/lib/audit/methods.ts
index add64414c6e8bdb7784054b1344cd4c999d6a465..b221f4a2f1e14c80671bca7308ca7916243395e2 100644
--- a/apps/meteor/ee/server/lib/audit/methods.ts
+++ b/apps/meteor/ee/server/lib/audit/methods.ts
@@ -88,11 +88,18 @@ Meteor.methods<ServerMethods>({
 		check(startDate, Date);
 		check(endDate, Date);
 
-		const user = await Meteor.userAsync();
+		const user = (await Meteor.userAsync()) as IUser;
 		if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) {
 			throw new Meteor.Error('Not allowed');
 		}
 
+		const userFields = {
+			_id: user._id,
+			username: user.username,
+			...(user.name && { name: user.name }),
+			...(user.avatarETag && { avatarETag: user.avatarETag }),
+		};
+
 		const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(visitor, agent, {
 			projection: { _id: 1 },
 		}).toArray();
@@ -118,7 +125,7 @@ Meteor.methods<ServerMethods>({
 		await AuditLog.insertOne({
 			ts: new Date(),
 			results: messages.length,
-			u: user,
+			u: userFields,
 			fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
 		});
 
@@ -128,11 +135,18 @@ Meteor.methods<ServerMethods>({
 		check(startDate, Date);
 		check(endDate, Date);
 
-		const user = await Meteor.userAsync();
+		const user = (await Meteor.userAsync()) as IUser;
 		if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) {
 			throw new Meteor.Error('Not allowed');
 		}
 
+		const userFields = {
+			_id: user._id,
+			username: user.username,
+			...(user.name && { name: user.name }),
+			...(user.avatarETag && { avatarETag: user.avatarETag }),
+		};
+
 		let rids;
 		let name;
 
@@ -169,9 +183,10 @@ Meteor.methods<ServerMethods>({
 		await AuditLog.insertOne({
 			ts: new Date(),
 			results: messages.length,
-			u: user,
+			u: userFields,
 			fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
 		});
+
 		updateCounter({ settingsId: 'Message_Auditing_Panel_Load_Count' });
 
 		return messages;
@@ -183,13 +198,24 @@ Meteor.methods<ServerMethods>({
 		if (!uid || !(await hasPermissionAsync(uid, 'can-audit-log'))) {
 			throw new Meteor.Error('Not allowed');
 		}
-		return AuditLog.find({
-			// 'u._id': userId,
-			ts: {
-				$gt: startDate,
-				$lt: endDate,
+		return AuditLog.find(
+			{
+				// 'u._id': userId,
+				ts: {
+					$gt: startDate,
+					$lt: endDate,
+				},
 			},
-		}).toArray();
+			{
+				projection: {
+					'u.services': 0,
+					'u.roles': 0,
+					'u.lastLogin': 0,
+					'u.statusConnection': 0,
+					'u.emails': 0,
+				},
+			},
+		).toArray();
 	},
 });
 
diff --git a/apps/meteor/server/lib/ldap/Manager.ts b/apps/meteor/server/lib/ldap/Manager.ts
index ab000b142225676868a0e83078cee8aa06f426a8..f0efcc04539d9b64115d38de1cd2f325550956f8 100644
--- a/apps/meteor/server/lib/ldap/Manager.ts
+++ b/apps/meteor/server/lib/ldap/Manager.ts
@@ -165,7 +165,7 @@ export class LDAPManager {
 
 		const { attribute: idAttribute, value: id } = uniqueId;
 		const username = this.slugifyUsername(ldapUser, usedUsername || id || '') || undefined;
-		const emails = this.getLdapEmails(ldapUser, username);
+		const emails = this.getLdapEmails(ldapUser, username).map((email) => email.trim());
 		const name = this.getLdapName(ldapUser) || undefined;
 
 		const userData: IImportUser = {
diff --git a/apps/meteor/server/methods/reportMessage.ts b/apps/meteor/server/methods/reportMessage.ts
index 05ac5aaf7e7bbfa6cd56af869c5139b0ed7c9ce8..14ef69189b337be0ebfd230bd3b6bcba2381cbe7 100644
--- a/apps/meteor/server/methods/reportMessage.ts
+++ b/apps/meteor/server/methods/reportMessage.ts
@@ -3,6 +3,7 @@ import type { IMessage } from '@rocket.chat/core-typings';
 import { ModerationReports, Rooms, Users, Messages } from '@rocket.chat/models';
 import type { ServerMethods } from '@rocket.chat/ui-contexts';
 import { check } from 'meteor/check';
+import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
 import { Meteor } from 'meteor/meteor';
 
 import { canAccessRoomAsync } from '../../app/authorization/server/functions/canAccessRoom';
@@ -82,3 +83,15 @@ Meteor.methods<ServerMethods>({
 		return true;
 	},
 });
+
+DDPRateLimiter.addRule(
+	{
+		type: 'method',
+		name: 'reportMessage',
+		userId() {
+			return true;
+		},
+	},
+	5,
+	60000,
+);
diff --git a/apps/meteor/server/methods/sendConfirmationEmail.ts b/apps/meteor/server/methods/sendConfirmationEmail.ts
index 8c7d056532d3958d3b54f3990b0336c853f41fb5..9ed7e0b99da28df36e2dbe113fdc42e7e7031f5f 100644
--- a/apps/meteor/server/methods/sendConfirmationEmail.ts
+++ b/apps/meteor/server/methods/sendConfirmationEmail.ts
@@ -2,6 +2,7 @@ import { Users } from '@rocket.chat/models';
 import type { ServerMethods } from '@rocket.chat/ui-contexts';
 import { Accounts } from 'meteor/accounts-base';
 import { check } from 'meteor/check';
+import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
 import { Meteor } from 'meteor/meteor';
 
 import { methodDeprecationLogger } from '../../app/lib/server/lib/deprecationWarningLogger';
@@ -31,3 +32,15 @@ Meteor.methods<ServerMethods>({
 		}
 	},
 });
+
+DDPRateLimiter.addRule(
+	{
+		type: 'method',
+		name: 'sendConfirmationEmail',
+		userId() {
+			return true;
+		},
+	},
+	5,
+	60000,
+);
diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts b/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts
index 19284b8e1e6b3a25a33cc1d8e8a4b38b89ffb4de..d036345663cd403cf8534026ad961cd5c15cc223 100644
--- a/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts
+++ b/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts
@@ -1,6 +1,7 @@
 import { Base64 } from '@rocket.chat/base64';
 import type { ISMSProvider, ServiceData, SMSProviderResult, SMSProviderResponse } from '@rocket.chat/core-typings';
 import { serverFetch as fetch } from '@rocket.chat/server-fetch';
+import type { Request } from 'express';
 
 import { settings } from '../../../../app/settings/server';
 import { SystemLogger } from '../../../lib/logger/system';
@@ -196,6 +197,10 @@ export class Mobex implements ISMSProvider {
 		};
 	}
 
+	validateRequest(_request: Request): boolean {
+		return true;
+	}
+
 	error(error: Error & { reason?: string }): SMSProviderResponse {
 		let message = '';
 		if (error.reason) {
diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts b/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts
index 3aff869a95a0c8c85cd6340372a40ce3e0dd7579..4a1c8d9d0ebf51c8e035f50a60bf793a037fd1ce 100644
--- a/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts
+++ b/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts
@@ -1,6 +1,7 @@
 import { api } from '@rocket.chat/core-services';
 import type { ISMSProvider, ServiceData, SMSProviderResponse, SMSProviderResult } from '@rocket.chat/core-typings';
 import { Users } from '@rocket.chat/models';
+import type { Request } from 'express';
 import filesize from 'filesize';
 import twilio from 'twilio';
 
@@ -244,6 +245,31 @@ export class Twilio implements ISMSProvider {
 		};
 	}
 
+	isRequestFromTwilio(signature: string, requestBody: object): boolean {
+		const authToken = settings.get<string>('SMS_Twilio_authToken');
+		const siteUrl = settings.get<string>('Site_Url');
+
+		if (!authToken || !siteUrl) {
+			SystemLogger.error(`(Twilio) -> URL or Twilio token not configured.`);
+			return false;
+		}
+
+		const twilioUrl = siteUrl.endsWith('/')
+			? `${siteUrl}api/v1/livechat/sms-incoming/twilio`
+			: `${siteUrl}/api/v1/livechat/sms-incoming/twilio`;
+		return twilio.validateRequest(authToken, signature, twilioUrl, requestBody);
+	}
+
+	validateRequest(request: Request): boolean {
+		// We're not getting original twilio requests on CI :p
+		if (process.env.TEST_MODE === 'true') {
+			return true;
+		}
+		const twilioHeader = request.headers['x-twilio-signature'] || '';
+		const twilioSignature = Array.isArray(twilioHeader) ? twilioHeader[0] : twilioHeader;
+		return this.isRequestFromTwilio(twilioSignature, request.body);
+	}
+
 	error(error: Error & { reason?: string }): SMSProviderResponse {
 		let message = '';
 		if (error.reason) {
diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts b/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts
index 3e78907bbf754d4a298f1b7cc492fa1f3e665012..aa42bacad624321125211d88c3ba469860f1db1a 100644
--- a/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts
+++ b/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts
@@ -2,6 +2,7 @@ import { api } from '@rocket.chat/core-services';
 import type { ISMSProvider, ServiceData, SMSProviderResponse } from '@rocket.chat/core-typings';
 import { Users } from '@rocket.chat/models';
 import { serverFetch as fetch } from '@rocket.chat/server-fetch';
+import type { Request } from 'express';
 import filesize from 'filesize';
 
 import { settings } from '../../../../app/settings/server';
@@ -162,6 +163,10 @@ export class Voxtelesys implements ISMSProvider {
 		};
 	}
 
+	validateRequest(_request: Request): boolean {
+		return true;
+	}
+
 	error(error: Error & { reason?: string }): SMSProviderResponse {
 		let message = '';
 		if (error.reason) {
diff --git a/apps/meteor/server/settings/message.ts b/apps/meteor/server/settings/message.ts
index 6ec6e33556559bdc0d76f8d178bfa325cd65a92f..520af87d2333a64f1a1473a918d5565119753000 100644
--- a/apps/meteor/server/settings/message.ts
+++ b/apps/meteor/server/settings/message.ts
@@ -32,7 +32,7 @@ export const createMessageSettings = () =>
 				],
 			});
 
-			await this.add('Message_Attachments_Strip_Exif', false, {
+			await this.add('Message_Attachments_Strip_Exif', true, {
 				type: 'boolean',
 				public: true,
 				i18nDescription: 'Message_Attachments_Strip_ExifDescription',
diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts
index e1ca05d1fbf216f56766479d3385b7ebf3adabc7..197a71f8e8f267ddeccc6677d03f165c797caa91 100644
--- a/apps/meteor/tests/end-to-end/api/methods.ts
+++ b/apps/meteor/tests/end-to-end/api/methods.ts
@@ -2030,6 +2030,13 @@ describe('Meteor.methods', () => {
 		let messageWithMarkdownId: IMessage['_id'];
 		let channelName: string;
 		const siteUrl = process.env.SITE_URL || process.env.TEST_API_URL || 'http://localhost:3000';
+		let testUser: TestUser<IUser>;
+		let testUserCredentials: Credentials;
+
+		before(async () => {
+			testUser = await createUser();
+			testUserCredentials = await login(testUser.username, password);
+		});
 
 		before('create room', (done) => {
 			channelName = `methods-test-channel-${Date.now()}`;
@@ -2125,13 +2132,14 @@ describe('Meteor.methods', () => {
 		after(() =>
 			Promise.all([
 				deleteRoom({ type: 'p', roomId: rid }),
+				deleteUser(testUser),
 				updatePermission('bypass-time-limit-edit-and-delete', ['bot', 'app']),
 				updateSetting('Message_AllowEditing_BlockEditInMinutes', 0),
 			]),
 		);
 
-		it('should update a message with a URL', (done) => {
-			void request
+		it('should update a message with a URL', async () => {
+			await request
 				.post(methodCall('updateMessage'))
 				.set(credentials)
 				.send({
@@ -2149,8 +2157,53 @@ describe('Meteor.methods', () => {
 					expect(res.body).to.have.a.property('message').that.is.a('string');
 					const data = JSON.parse(res.body.message);
 					expect(data).to.have.a.property('msg').that.is.an('string');
+				});
+		});
+
+		it('should fail if user does not have permissions to update a message with the same content', async () => {
+			await request
+				.post(methodCall('updateMessage'))
+				.set(testUserCredentials)
+				.send({
+					message: JSON.stringify({
+						method: 'updateMessage',
+						params: [{ _id: messageId, rid, msg: 'test message with https://github.com' }],
+						id: 'id',
+						msg: 'method',
+					}),
 				})
-				.end(done);
+				.expect('Content-Type', 'application/json')
+				.expect(200)
+				.expect((res) => {
+					expect(res.body).to.have.a.property('success', true);
+					expect(res.body).to.have.a.property('message').that.is.a('string');
+					const data = JSON.parse(res.body.message);
+					expect(data).to.have.a.property('msg').that.is.an('string');
+					expect(data.error).to.have.a.property('error', 'error-action-not-allowed');
+				});
+		});
+
+		it('should fail if user does not have permissions to update a message with different content', async () => {
+			await request
+				.post(methodCall('updateMessage'))
+				.set(testUserCredentials)
+				.send({
+					message: JSON.stringify({
+						method: 'updateMessage',
+						params: [{ _id: messageId, rid, msg: 'updating test message with https://github.com' }],
+						id: 'id',
+						msg: 'method',
+					}),
+				})
+				.expect('Content-Type', 'application/json')
+				.expect(200)
+				.expect((res) => {
+					expect(res.body).to.have.a.property('success', true);
+					expect(res.body).to.have.a.property('message').that.is.a('string');
+					const data = JSON.parse(res.body.message);
+					expect(data).to.have.a.property('msg').that.is.an('string');
+					expect(data.error).to.have.a.property('error', 'error-action-not-allowed');
+				});
 		});
 
 		it('should add a quote attachment to a message', async () => {
@@ -3295,4 +3348,107 @@ describe('Meteor.methods', () => {
 				.end(done);
 		});
 	});
+	(IS_EE ? describe : describe.skip)('[@auditGetAuditions] EE', () => {
+		let testUser: TestUser<IUser>;
+		let testUserCredentials: Credentials;
+
+		const now = new Date();
+		const startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime();
+		const endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999).getTime();
+
+		before('create test user', async () => {
+			testUser = await createUser();
+			testUserCredentials = await login(testUser.username, password);
+		});
+
+		before('generate audits data', async () => {
+			await request
+				.post(methodCall('auditGetMessages'))
+				.set(credentials)
+				.send({
+					message: JSON.stringify({
+						method: 'auditGetMessages',
+						params: [
+							{
+								type: '',
+								msg: 'test1234',
+								startDate: { $date: startDate },
+								endDate: { $date: endDate },
+								rid: 'GENERAL',
+								users: [],
+							},
+						],
+						id: '14',
+						msg: 'method',
+					}),
+				});
+		});
+
+		after(() => Promise.all([deleteUser(testUser)]));
+
+		it('should fail if the user does not have permissions to get auditions', async () => {
+			await request
+				.post(methodCall('auditGetAuditions'))
+				.set(testUserCredentials)
+				.send({
+					message: JSON.stringify({
+						method: 'auditGetAuditions',
+						params: [
+							{
+								startDate: { $date: startDate },
+								endDate: { $date: endDate },
+							},
+						],
+						id: '18',
+						msg: 'method',
+					}),
+				})
+				.expect('Content-Type', 'application/json')
+				.expect(200)
+				.expect((res) => {
+					expect(res.body).to.have.a.property('message');
+					const data = JSON.parse(res.body.message);
+					expect(data).to.have.a.property('error');
+					expect(data.error).to.have.a.property('error', 'Not allowed');
+				});
+		});
+
+		it('should not return more user data than necessary - e.g. passwords, hashes, tokens', async () => {
+			await request
+				.post(methodCall('auditGetAuditions'))
+				.set(credentials)
+				.send({
+					message: JSON.stringify({
+						method: 'auditGetAuditions',
+						params: [
+							{
+								startDate: { $date: startDate },
+								endDate: { $date: endDate },
+							},
+						],
+						id: '18',
+						msg: 'method',
+					}),
+				})
+				.expect('Content-Type', 'application/json')
+				.expect(200)
+				.expect((res) => {
+					expect(res.body).to.have.a.property('success', true);
+					expect(res.body).to.have.a.property('message').that.is.a('string');
+					const data = JSON.parse(res.body.message);
+					expect(data).to.have.a.property('result').that.is.an('array');
+					expect(data.result.length).to.be.greaterThan(0);
+					expect(data).to.have.a.property('msg', 'result');
+					expect(data).to.have.a.property('id', '18');
+					data.result.forEach((item: any) => {
+						expect(item).to.have.all.keys('_id', 'ts', 'results', 'u', 'fields', '_updatedAt');
+						expect(item.u).to.not.have.property('services');
+						expect(item.u).to.not.have.property('roles');
+						expect(item.u).to.not.have.property('lastLogin');
+						expect(item.u).to.not.have.property('statusConnection');
+						expect(item.u).to.not.have.property('emails');
+					});
+				});
+		});
+	});
 });
diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts
index a8d64b1f4c7d72fbdf9a2c13cc0da19be8e04145..b502bca6add821d2ff491c513fca743ecfb7a95d 100644
--- a/apps/meteor/tests/end-to-end/api/rooms.ts
+++ b/apps/meteor/tests/end-to-end/api/rooms.ts
@@ -1024,7 +1024,6 @@ describe('[Rooms]', () => {
 				.end(done);
 		});
 	});
-
 	describe('[/rooms.info]', () => {
 		let testChannel: IRoom;
 		let testGroup: IRoom;
diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts
index d6112dd2416bbc5615aa3d3e54fb18733f212ade..ea2aa5baa99ba3ea9a465db1cff8a91e51e4ab6e 100644
--- a/apps/meteor/tests/end-to-end/api/users.ts
+++ b/apps/meteor/tests/end-to-end/api/users.ts
@@ -2624,18 +2624,37 @@ describe('[Users]', () => {
 	});
 
 	describe('[/users.forgotPassword]', () => {
+		it('should return an error when "Accounts_PasswordReset" is disabled', (done) => {
+			void updateSetting('Accounts_PasswordReset', false).then(() => {
+				void request
+					.post(api('users.forgotPassword'))
+					.send({
+						email: adminEmail,
+					})
+					.expect('Content-Type', 'application/json')
+					.expect(400)
+					.expect((res) => {
+						expect(res.body).to.have.property('success', false);
+						expect(res.body).to.have.property('error', 'Password reset is not enabled');
+					})
+					.end(done);
+			});
+		});
+
 		it('should send email to user (return success), when is a valid email', (done) => {
-			void request
-				.post(api('users.forgotPassword'))
-				.send({
-					email: adminEmail,
-				})
-				.expect('Content-Type', 'application/json')
-				.expect(200)
-				.expect((res) => {
-					expect(res.body).to.have.property('success', true);
-				})
-				.end(done);
+			void updateSetting('Accounts_PasswordReset', true).then(() => {
+				void request
+					.post(api('users.forgotPassword'))
+					.send({
+						email: adminEmail,
+					})
+					.expect('Content-Type', 'application/json')
+					.expect(200)
+					.expect((res) => {
+						expect(res.body).to.have.property('success', true);
+					})
+					.end(done);
+			});
 		});
 
 		it('should not send email to user(return error), when is a invalid email', (done) => {
diff --git a/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts b/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f3c5d281aefbcdb9ef27ce9ac4cf5d3c9487857e
--- /dev/null
+++ b/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts
@@ -0,0 +1,211 @@
+import crypto from 'crypto';
+
+import { expect } from 'chai';
+import proxyquire from 'proxyquire';
+import sinon from 'sinon';
+
+const settingsStub = {
+	get: sinon.stub(),
+};
+
+const twilioStub = {
+	validateRequest: sinon.stub(),
+	isRequestFromTwilio: sinon.stub(),
+};
+
+const { Twilio } = proxyquire.noCallThru().load('../../../../../../server/services/omnichannel-integrations/providers/twilio.ts', {
+	'../../../../app/settings/server': { settings: settingsStub },
+	'../../../../app/utils/server/restrictions': { fileUploadIsValidContentType: sinon.stub() },
+	'../../../lib/i18n': { i18n: sinon.stub() },
+	'../../../lib/logger/system': { SystemLogger: { error: sinon.stub() } },
+});
+
+/**
+ * Get a valid Twilio signature for a request
+ *
+ * @param {String} authToken your Twilio AuthToken
+ * @param {String} url your webhook URL
+ * @param {Object} params the included request parameters
+ */
+function getSignature(authToken: string, url: string, params: Record<string, any>): string {
+	// get all request parameters
+	const data = Object.keys(params)
+		// sort them
+		.sort()
+		// concatenate them to a string
+
+		.reduce((acc, key) => acc + key + params[key], url);
+
+	return (
+		crypto
+			// sign the string with sha1 using your AuthToken
+			.createHmac('sha1', authToken)
+			.update(Buffer.from(data, 'utf-8'))
+			// base64 encode it
+			.digest('base64')
+	);
+}
+
+describe('Twilio Request Validation', () => {
+	beforeEach(() => {
+		settingsStub.get.reset();
+		twilioStub.validateRequest.reset();
+		twilioStub.isRequestFromTwilio.reset();
+	});
+
+	it('should not validate a request when process.env.TEST_MODE is true', () => {
+		process.env.TEST_MODE = 'true';
+
+		const twilio = new Twilio();
+		const request = {
+			headers: {
+				'x-twilio-signature': 'test',
+			},
+		};
+
+		expect(twilio.validateRequest(request)).to.be.true;
+	});
+
+	it('should not validate a request when process.env.TEST_MODE is true', () => {
+		process.env.TEST_MODE = 'true';
+
+		const twilio = new Twilio();
+		const request = {
+			headers: {
+				'x-twilio-signature': 'test',
+			},
+		};
+
+		expect(twilio.validateRequest(request)).to.be.true;
+	});
+
+	it('should validate a request when process.env.TEST_MODE is false', () => {
+		process.env.TEST_MODE = 'false';
+
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test');
+		settingsStub.get.withArgs('Site_Url').returns('https://example.com');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {
+				'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody),
+			},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.true;
+	});
+
+	it('should reject a request where signature doesnt match', () => {
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test');
+		settingsStub.get.withArgs('Site_Url').returns('https://example.com');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {
+				'x-twilio-signature': getSignature('anotherAuthToken', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody),
+			},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.false;
+	});
+
+	it('should reject a request where signature is missing', () => {
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test');
+		settingsStub.get.withArgs('Site_Url').returns('https://example.com');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.false;
+	});
+
+	it('should reject a request where the signature doesnt correspond body', () => {
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test');
+		settingsStub.get.withArgs('Site_Url').returns('https://example.com');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {
+				'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', {}),
+			},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.false;
+	});
+
+	it('should return false if URL is not provided', () => {
+		process.env.TEST_MODE = 'false';
+
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test');
+		settingsStub.get.withArgs('Site_Url').returns('');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {
+				'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody),
+			},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.false;
+	});
+
+	it('should return false if authToken is not provided', () => {
+		process.env.TEST_MODE = 'false';
+
+		settingsStub.get.withArgs('SMS_Twilio_authToken').returns('');
+		settingsStub.get.withArgs('Site_Url').returns('https://example.com');
+
+		const twilio = new Twilio();
+		const requestBody = {
+			To: 'test',
+			From: 'test',
+			Body: 'test',
+		};
+
+		const request = {
+			headers: {
+				'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody),
+			},
+			body: requestBody,
+		};
+
+		expect(twilio.validateRequest(request)).to.be.false;
+	});
+});
diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json
index a9f4fdd293e309d564e3f6b4f28dfe9317048a36..3c0c97198b7f854bf09aebfb638879a9b9f66543 100644
--- a/packages/core-typings/package.json
+++ b/packages/core-typings/package.json
@@ -25,7 +25,8 @@
 		"@rocket.chat/apps-engine": "1.44.0",
 		"@rocket.chat/icons": "^0.36.0",
 		"@rocket.chat/message-parser": "workspace:^",
-		"@rocket.chat/ui-kit": "workspace:~"
+		"@rocket.chat/ui-kit": "workspace:~",
+		"@types/express": "^4.17.21"
 	},
 	"volta": {
 		"extends": "../../package.json"
diff --git a/packages/core-typings/src/omnichannel/sms.ts b/packages/core-typings/src/omnichannel/sms.ts
index 7ff7a4768a134fa11aa12f1f45cad9a5831a9966..49364da2b8c3630f08afe8806e087c085476ab05 100644
--- a/packages/core-typings/src/omnichannel/sms.ts
+++ b/packages/core-typings/src/omnichannel/sms.ts
@@ -1,3 +1,5 @@
+import type { Request } from 'express';
+
 type ServiceMedia = {
 	url: string;
 	contentType: string;
@@ -27,6 +29,7 @@ export interface ISMSProviderConstructor {
 
 export interface ISMSProvider {
 	parse(data: unknown): ServiceData;
+	validateRequest(request: Request): boolean;
 
 	sendBatch?(from: string, to: string[], message: string): Promise<SMSProviderResult>;
 	response(): SMSProviderResponse;
diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts
index 1c0b6a360f7b6052cd1938242d3c863f02f17f5e..868fd5850157f90b3b08b4ead861d01c156d8075 100644
--- a/packages/rest-typings/src/v1/rooms.ts
+++ b/packages/rest-typings/src/v1/rooms.ts
@@ -527,6 +527,62 @@ const roomsImagesPropsSchema = {
 
 export const isRoomsImagesProps = ajv.compile<RoomsImagesProps>(roomsImagesPropsSchema);
 
+export type RoomsCleanHistoryProps = {
+	roomId: IRoom['_id'];
+	latest: string;
+	oldest: string;
+	inclusive?: boolean;
+	excludePinned?: boolean;
+	filesOnly?: boolean;
+	users?: IUser['username'][];
+	limit?: number;
+	ignoreDiscussion?: boolean;
+	ignoreThreads?: boolean;
+};
+
+const roomsCleanHistorySchema = {
+	type: 'object',
+	properties: {
+		roomId: {
+			type: 'string',
+		},
+		latest: {
+			type: 'string',
+		},
+		oldest: {
+			type: 'string',
+		},
+		inclusive: {
+			type: 'boolean',
+		},
+		excludePinned: {
+			type: 'boolean',
+		},
+		filesOnly: {
+			type: 'boolean',
+		},
+		users: {
+			type: 'array',
+			items: {
+				type: 'string',
+			},
+		},
+		limit: {
+			type: 'number',
+		},
+		ignoreDiscussion: {
+			type: 'boolean',
+		},
+		ignoreThreads: {
+			type: 'boolean',
+		},
+	},
+	required: ['roomId', 'latest', 'oldest'],
+	additionalProperties: false,
+};
+
+export const isRoomsCleanHistoryProps = ajv.compile<RoomsCleanHistoryProps>(roomsCleanHistorySchema);
+
 export type RoomsEndpoints = {
 	'/v1/rooms.autocomplete.channelAndPrivate': {
 		GET: (params: RoomsAutoCompleteChannelAndPrivateProps) => {
@@ -559,18 +615,7 @@ export type RoomsEndpoints = {
 	};
 
 	'/v1/rooms.cleanHistory': {
-		POST: (params: {
-			roomId: IRoom['_id'];
-			latest: string;
-			oldest: string;
-			inclusive?: boolean;
-			excludePinned?: boolean;
-			filesOnly?: boolean;
-			users?: IUser['username'][];
-			limit?: number;
-			ignoreDiscussion?: boolean;
-			ignoreThreads?: boolean;
-		}) => { _id: IRoom['_id']; count: number; success: boolean };
+		POST: (params: RoomsCleanHistoryProps) => { _id: IRoom['_id']; count: number; success: boolean };
 	};
 
 	'/v1/rooms.createDiscussion': {
diff --git a/yarn.lock b/yarn.lock
index a04c45ee1f6442fea3ea0b002a8d6a127014978d..84ca676c886c9f533a674c1f8907d46c2d6f1e4c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8645,6 +8645,7 @@ __metadata:
     "@rocket.chat/icons": ^0.36.0
     "@rocket.chat/message-parser": "workspace:^"
     "@rocket.chat/ui-kit": "workspace:~"
+    "@types/express": ^4.17.21
     eslint: ~8.45.0
     mongodb: ^4.17.2
     prettier: ~2.8.8
@@ -8968,10 +8969,10 @@ __metadata:
     "@rocket.chat/icons": "*"
     "@rocket.chat/prettier-config": "*"
     "@rocket.chat/styled": "*"
-    "@rocket.chat/ui-avatar": 5.0.0-rc.6
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
-    "@rocket.chat/ui-kit": 0.36.0-rc.0
-    "@rocket.chat/ui-video-conf": 9.0.0-rc.6
+    "@rocket.chat/ui-avatar": 5.0.0
+    "@rocket.chat/ui-contexts": 9.0.0
+    "@rocket.chat/ui-kit": 0.36.0
+    "@rocket.chat/ui-video-conf": 9.0.0
     "@tanstack/react-query": "*"
     react: "*"
     react-dom: "*"
@@ -9060,8 +9061,8 @@ __metadata:
     "@rocket.chat/fuselage-tokens": "*"
     "@rocket.chat/message-parser": 0.31.29
     "@rocket.chat/styled": "*"
-    "@rocket.chat/ui-client": 9.0.0-rc.6
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
+    "@rocket.chat/ui-client": 9.0.0
+    "@rocket.chat/ui-contexts": 9.0.0
     katex: "*"
     react: "*"
   languageName: unknown
@@ -10281,7 +10282,7 @@ __metadata:
     typescript: ~5.3.3
   peerDependencies:
     "@rocket.chat/fuselage": "*"
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
+    "@rocket.chat/ui-contexts": 9.0.0
     react: ~17.0.2
   languageName: unknown
   linkType: soft
@@ -10334,7 +10335,7 @@ __metadata:
     "@rocket.chat/fuselage": "*"
     "@rocket.chat/fuselage-hooks": "*"
     "@rocket.chat/icons": "*"
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
+    "@rocket.chat/ui-contexts": 9.0.0
     react: ~17.0.2
   languageName: unknown
   linkType: soft
@@ -10510,8 +10511,8 @@ __metadata:
     "@rocket.chat/fuselage-hooks": "*"
     "@rocket.chat/icons": "*"
     "@rocket.chat/styled": "*"
-    "@rocket.chat/ui-avatar": 5.0.0-rc.6
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
+    "@rocket.chat/ui-avatar": 5.0.0
+    "@rocket.chat/ui-contexts": 9.0.0
     react: ^17.0.2
     react-dom: ^17.0.2
   languageName: unknown
@@ -10600,8 +10601,8 @@ __metadata:
     typescript: ~5.3.3
   peerDependencies:
     "@rocket.chat/layout": "*"
-    "@rocket.chat/tools": 0.2.2-rc.0
-    "@rocket.chat/ui-contexts": 9.0.0-rc.6
+    "@rocket.chat/tools": 0.2.2
+    "@rocket.chat/ui-contexts": 9.0.0
     "@tanstack/react-query": "*"
     react: "*"
     react-hook-form: "*"
@@ -13548,6 +13549,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/express@npm:^4.17.21":
+  version: 4.17.21
+  resolution: "@types/express@npm:4.17.21"
+  dependencies:
+    "@types/body-parser": "*"
+    "@types/express-serve-static-core": ^4.17.33
+    "@types/qs": "*"
+    "@types/serve-static": "*"
+  checksum: fb238298630370a7392c7abdc80f495ae6c716723e114705d7e3fb67e3850b3859bbfd29391463a3fb8c0b32051847935933d99e719c0478710f8098ee7091c5
+  languageName: node
+  linkType: hard
+
 "@types/fibers@npm:^3.1.3":
   version: 3.1.3
   resolution: "@types/fibers@npm:3.1.3"