Headline
CVE-2023-43797: Merge pull request from GHSA-v6wg-q866-h73x · bigbluebutton/bigbluebutton@304bc85
BigBlueButton is an open-source virtual classroom. Prior to versions 2.6.11 and 2.7.0-beta.3, Guest Lobby was vulnerable to cross-site scripting when users wait to enter the meeting due to inserting unsanitized messages to the element using unsafe innerHTML. Text sanitizing was added for lobby messages starting in versions 2.6.11 and 2.7.0-beta.3. There are no known workarounds.
25 changes: 25 additions & 0 deletions bigbluebutton-html5/imports/api/common/server/helpers.js
@@ -1,9 +1,34 @@
import Users from '/imports/api/users’;
import Logger from '/imports/startup/server/logger’;
import RegexWebUrl from '/imports/utils/regex-weburl’;
const MSG_DIRECT_TYPE = 'DIRECT’;
const NODE_USER = 'nodeJSapp’;
const HTML_SAFE_MAP = {
'<’: '<’,
'>’: '>’,
'"’: '"’,
"’": '’’,
};
export const parseMessage = (message) => {
let parsedMessage = message || '’;
parsedMessage = parsedMessage.trim();
// Replace <br/> with \n\r
parsedMessage = parsedMessage.replace(/<br\s*[\\/]?>/gi, ‘\n\r’);
// Sanitize. See: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
parsedMessage = parsedMessage.replace(/[<>’"]/g, © => HTML_SAFE_MAP[c]);
// Replace flash links to flash valid ones
parsedMessage = parsedMessage.replace(RegexWebUrl, “<a href=’event:$&’><u>$&</u></a>”);
return parsedMessage;
};
export const spokeTimeoutHandles = {};
export const clearSpokeTimeout = (meetingId, userId) => {
if (spokeTimeoutHandles[`${meetingId}-${userId}`]) {
Expand Down
@@ -1,32 +1,9 @@
import { Meteor } from 'meteor/meteor’;
import { check } from 'meteor/check’;
import RedisPubSub from '/imports/startup/server/redis’;
import RegexWebUrl from '/imports/utils/regex-weburl’;
import { extractCredentials } from '/imports/api/common/server/helpers’;
import Logger from '/imports/startup/server/logger’;
const HTML_SAFE_MAP = {
'<’: '<’,
'>’: '>’,
'"’: '"’,
"’": '’’,
};
const parseMessage = (message) => {
let parsedMessage = message || '’;
parsedMessage = parsedMessage.trim();
// Replace <br/> with \n\r
parsedMessage = parsedMessage.replace(/<br\s*[\\/]?>/gi, ‘\n\r’);
// Sanitize. See: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
parsedMessage = parsedMessage.replace(/[<>’"]/g, © => HTML_SAFE_MAP[c]);
// Replace flash links to flash valid ones
parsedMessage = parsedMessage.replace(RegexWebUrl, “<a href=’event:$&’><u>$&</u></a>”);
return parsedMessage;
};
import { extractCredentials, parseMessage } from '/imports/api/common/server/helpers’;
import Logger from '/imports/startup/server/logger’;
export default function sendGroupChatMsg(chatId, message) {
const REDIS_CONFIG = Meteor.settings.private.redis;
Expand Down
Expand Up
@@ -2,7 +2,7 @@ import { GroupChatMsg } from '/imports/api/group-chat-msg’;
import GroupChat from '/imports/api/group-chat’;
import Logger from '/imports/startup/server/logger’;
import flat from 'flat’;
import { parseMessage } from './addGroupChatMsg’;
import { parseMessage } from '/imports/api/common/server/helpers’;
export default async function addBulkGroupChatMsgs(msgs) {
if (!msgs.length) return;
Expand Down
Expand Up
@@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor’;
import { check } from 'meteor/check’;
import RedisPubSub from '/imports/startup/server/redis’;
import Logger from '/imports/startup/server/logger’;
import { extractCredentials } from '/imports/api/common/server/helpers’;
import { extractCredentials, parseMessage } from '/imports/api/common/server/helpers’;
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
Expand All
@@ -16,8 +16,7 @@ export default function setGuestLobbyMessage(message) {
check(meetingId, String);
check(requesterUserId, String);
const payload = { message };
const payload = { message: parseMessage(message) };
Logger.info(`User=${requesterUserId} set guest lobby message to ${message}`);
Expand Down
Expand Up
@@ -2,7 +2,8 @@ import { Meteor } from 'meteor/meteor’;
import { check } from 'meteor/check’;
import RedisPubSub from '/imports/startup/server/redis’;
import Logger from '/imports/startup/server/logger’;
import { extractCredentials } from '/imports/api/common/server/helpers’;
import { extractCredentials, parseMessage } from '/imports/api/common/server/helpers’;
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
Expand All
@@ -17,7 +18,7 @@ export default function setPrivateGuestLobbyMessage(message, guestId) {
check(meetingId, String);
check(requesterUserId, String);
const payload = { guestId, message };
const payload = { guestId, message: parseMessage(message) };
Logger.info(`User=${requesterUserId} sent a private guest lobby message to guest user=${guestId}`);
Expand Down
0 comments on commit 304bc85
Please sign in to comment.