Forum teuk.org

mbweb β€” Audit and fixes v0.2.x (April 2026)

in Mediabot Β· started by TeuK Β· yesterday

TeuK Β· yesterday

mbweb β€” Audit and fixes v0.2.x (April 2026)

Context

mbweb is the Node.js/Express web console for Mediabot v3. This article documents the bugs identified and fixed during the audit of snapshot 20260427-2350.


Fixes

#1 β€” Prometheus metrics block never rendered

File: app.js

fetchMetrics() existed in the codebase but was never called from the GET / handler. data.metrics was therefore always undefined, and the β€œBot Mediabot β€” live metrics” section never appeared on the homepage.

Fix: parallel call via Promise.all alongside getDashboardData(). Metric names were also aligned to the actual names exposed by the Prometheus endpoint (mediabot_up, mediabot_current_channels, mediabot_partyline_sessions_current, etc.).


#2a β€” getCommands(): SQL crash on category filter

File: lib/mediabotRepository.js

When the PUBLIC_COMMANDS_CATEGORY table is absent (catExists = false), catJoin is empty string, but the if (category) block was still pushing pcc.description = ? into the WHERE clause β€” referencing a non-existent alias.

Fix:

// before
if (category) {
// after
if (category && catExists) {

#2b β€” getAllUsersWithRoles(): ORDER BY ul.level without join

File: lib/mediabotRepository.js

ORDER BY COALESCE(ul.level, ...) unconditionally referenced the ul alias from USER_LEVEL, even when the LEFT JOIN was not generated (table absent or missing columns).

Fix: conditional orderBy variable:

const orderBy = joinLevel
  ? 'COALESCE(ul.level, u.id_user_level, 999)'
  : 'COALESCE(u.id_user_level, 999)';

#3 β€” /api/status public endpoint leaking DB credentials

File: routes/api.js

GET /api/status was accessible without authentication and returned db.user, db.host, db.name via the ...data spread from getDashboardData(). GET /health also leaked the full session user object.

Fix:

  • /api/status: added requireLogin + isOwner() guard + try/catch
  • /health: response reduced to { ok, service, timestamp }

#4 β€” Duplicate column cache out of sync

Files: lib/db.js / lib/mediabotRepository.js

db.js maintained _columnCache via tableColumns(). mediabotRepository.js maintained a separate _repoColumnCache via getColumns() with its own TTL. Calling clearColumnCache() from db.js left the repository cache stale.

Fix: removed _repoColumnCache and _REPO_CACHE_TTL from the repository. getColumns() now delegates to tableColumns() from db.js β€” single source of truth.


#5 β€” err.message leaked in login redirect URL

File: routes/auth.js

The catch block in POST /login was including err.message in the ?error= redirect parameter, potentially exposing internal details (MySQL message, table name, partial stack) in the URL visible to the user.

Fix: generic user-facing message; err.message preserved in journalctl logs only.


Status after audit

# Category Status
1 Bug β€” homepage metrics βœ… fixed
2a Bug β€” SQL getCommands βœ… fixed
2b Bug β€” SQL getAllUsersWithRoles βœ… fixed
3 Security β€” public endpoints βœ… fixed
4 Refactor β€” duplicate column cache βœ… fixed
5 Security β€” err.message leak βœ… fixed

Next steps: dead code in viewHelpers.js, incomplete nav (Quotes / Commands / Network), app.js split into route files, CSRF on login form.

You must be logged in to reply.