Nine Digits and You're In the Meeting — JavaScript Bug Hunt

Modelled on Zoom's 2020 "Zoombombing" wave: meeting IDs were short numeric codes, passwords were off by default, and there was no rate limit on joining.

  • Language: JavaScript
  • Layer: Backend
  • Difficulty: Medium
  • Concepts: Security, Access Control
  • Modelled on: Zoom · 2020
  • Visible tests: the right passcode admits; a wrong passcode is denied; repeated failures lock the meeting
  • Reward: 50 XP for a complete fix

Briefing

Modelled on Zoom's 2020 "Zoombombing" wave: meeting IDs were short numeric codes, passwords were off by default, and there was no rate limit on joining. Automated tools guessed live meeting IDs and dropped strangers into calls.

meetings.js admits anyone who supplies an existing meeting id.

Fix joinMeeting so a passcode is required and repeated failed attempts are throttled.

Bug report

BUG-ZOOM2020 · Priority: Critical · Reported by: trust & safety

joinMeeting(meetings, attempts, meetingId, passcode) must return { status, admitted }:

  • "not-found" when the meeting does not exist
  • "locked" when that client has already made 5 failed attempts
  • "denied" when the passcode does not match (and the failure is recorded)
  • "ok" with admitted true when it matches

attempts is a plain object mapping meetingId -> failed count.

Observed: any known meeting id admits the caller, and there is no attempt limit at all.

Logs

[meet] admitted anonymous joiner to 8471120394 (no passcode set)
[meet] 41,000 join attempts from one source in 6 minutes

The code as shipped

src/meet/meetings.js (editable)

exports.joinMeeting = function (meetings, attempts, meetingId, passcode) {
  var meeting = meetings[meetingId];
  if (!meeting) return { status: "not-found", admitted: false };
  return { status: "ok", admitted: true };
};

Read-only context: src/meet/POLICY.js.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.