T05 · Unauthorized Access and Privilege Escalation
- Location
lib/server.js:5088- Finding
Default unauthenticated server binding exposes sensitive APIs and job controls to remote clients
- Content
View full analysis
Vulnerability Details
File Location:
lib/server.js:214,lib/server.js:5088-5103,lib/server.js:5118-5147,lib/server.js:5427-5433; source counterpartssrc/config.js:196-228,src/index.js:288-312,src/index.js:324-354,src/index.js:670-675
Vulnerability Type: Missing authentication combined with unrestricted network binding
Risk Level: HighComplete Code Snippets
The effective bundled entry point defaults authentication to
none:js server: { port: parseInt(process.env.PORT || fileConfig.server?.port || "3333", 10), host: process.env.HOST || fileConfig.server?.host || "localhost" }, // ... auth: { mode: process.env.DASHBOARD_AUTH_MODE || fileConfig.auth?.mode || "none",The request handler only performs authentication when the mode is not
none:js var server = http.createServer(async (req, res) => { res.setHeader("Access-Control-Allow-Origin", "*"); const urlParts = req.url.split("?"); const pathname = urlParts[0]; const query = new URLSearchParams(urlParts[1] || ""); if (pathname === "/api/health") { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ status: "ok", port: PORT, timestamp: (/* @__PURE__ */ new Date()).toISOString() })); return; } const isPublicPath = AUTH_CONFIG.publicPaths.some( (p) => pathname === p || pathname.startsWith(p + "/") ); if (!isPublicPath && AUTH_CONFIG.mode !== "none") { const authResult = checkAuth(req, AUTH_CONFIG); if (!authResult.authorized) { console.log(`[AUTH] Denied: ${authResult.reason} (path: ${pathname})`); res.writeHead(403, { "Content-Type": "text/html" }); res.end(getUnauthorizedPage(authResult.reason, authResult.user, AUTH_CONFIG)); return; } req.authUser = authResult.user; }Sensitive routes are then reachable, including session details:
js if (pathname === "/api/status") { handleApi(req, res); } else if (pathname === ...[truncated 3419 chars]- Remediation
View remediation
Remediation Suggestions
- Enforce the configured host when starting the server:
js server.listen(PORT, CONFIG.server.host, () => { // ... });- Preserve
localhostor an explicit loopback address as the default binding. - Refuse startup when authentication is
noneand the selected bind address is not loopback. - Require authentication for all endpoints containing session, memory, cron, system, project, or job information.
- Apply separate authorization checks to job mutation endpoints, rather than treating dashboard access as sufficient authorization.
- Restrict mutation endpoints to the expected HTTP methods and consider CSRF protections when browser-based authentication is used.
- Remove the wildcard CORS policy or replace it with an explicit allowlist appropriate to the deployment.
- Add integration tests that verify:
- Default startup accepts only loopback connections.
- Non-loopback binding fails unless a secure authentication mode is configured.
- Every sensitive and state-changing endpoint rejects unauthenticated requests.
