T05 · Unauthorized Access and Privilege Escalation
- Location
server.js:2597- Finding
Unauthenticated browser session management and cross-user session deletion
- Content
View full analysis
{ try { const userId = normalizeUserId(req.params.userId); const session = sessions.get(userId); if (session) { await clearSessionDownloads(session); await session.context.close(); sessions.delete(userId); // Remove any lingering tab locks for the session for (const [listItemId, group] of session.tabGroups) { for (const tabId of group.keys()) { const lock = tabLocks.get(tabId); if (lock) { lock.drain(); tabLocks.delete(tabId); } } } refreshTabLockQueueDepth(); refreshActiveTabsGauge(); log('info', 'session closed', { userId }); } if (sessions.size === 0) scheduleBrowserIdleShutdown(); res.json({ ok: true }); } catch (err) { log('error', 'session close failed', { error: err.message }); handleRouteError(err, req, res); } }); ``` The server is started without an explicit loopback-only host: ```js const server = app.listen(PORT, async () => { ``` ### Technical Analysis The REST API treats request-supplied `userId` values as identities, but most routes do not authenticate the caller or verify that the caller owns the requested user, session, or tab. Only the cookie-import route and `/stop` have dedicated secret checks. In particular, `DELETE /sessions/:userId` accepts the target identity entirely from the URL and closes the associated browser context without authorization. The omission of a host argument in `app.listen` normally exposes the service on all available interfaces rather than restricting it to `127.0.0.1`. The same trust model affects tab creation, navigation, snapshots, screenshots, downloads, evaluation, and othe ...[truncated 1564 chars]- Remediation
View remediation
