[object Object]

← back to Norma Platform

SECURITY incident 2026-07-29: agent-base fail-closed on empty AUTH_PASSWORD + bind 127.0.0.1 by default (was the empty-password all-interfaces RCE vector)

19d20a6a903ce7149da80b3d7d447fd01a54dc38 · 2026-07-29 21:18:31 -0700 · Steve

Files touched

Diff

commit 19d20a6a903ce7149da80b3d7d447fd01a54dc38
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 29 21:18:31 2026 -0700

    SECURITY incident 2026-07-29: agent-base fail-closed on empty AUTH_PASSWORD + bind 127.0.0.1 by default (was the empty-password all-interfaces RCE vector)
---
 agents/shared/agent-base.js | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/agents/shared/agent-base.js b/agents/shared/agent-base.js
index e5ff800..429361a 100644
--- a/agents/shared/agent-base.js
+++ b/agents/shared/agent-base.js
@@ -128,7 +128,8 @@ function createAgentServer({ name, port, skills = {}, cronJobs = [], dashboard =
     const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
     const [user, pass] = decoded.split(':');
 
-    if (user !== AUTH_USER || pass !== AUTH_PASS) {
+    // Defense-in-depth: an empty AUTH_PASS must never authenticate (incident 2026-07-29).
+    if (!AUTH_PASS || user !== AUTH_USER || pass !== AUTH_PASS) {
       return res.status(403).json({ error: 'Invalid credentials' });
     }
 
@@ -365,8 +366,16 @@ setTimeout(()=>location.reload(),15000);
   // ──────────────────────────────────────
   function start() {
     registerFallbacks(); // after caller's custom routes → no shadowing
-    app.listen(port, () => {
-      console.log(`[${new Date().toISOString()}] [${name}] Agent running on port ${port}`);
+    // Fail-closed: refuse to start with an empty password. An unset AUTH_PASSWORD +
+    // the old all-interfaces bind was the credential-stealer RCE vector (incident 2026-07-29).
+    if (!AUTH_PASS) {
+      console.error(`[${new Date().toISOString()}] [${name}] FATAL: AUTH_PASSWORD is empty — refusing to start (incident 2026-07-29 empty-password exposure). Set AUTH_PASSWORD in this agent's .env.`);
+      process.exit(1);
+    }
+    // Bind loopback by default; a fronting proxy can widen via BIND_HOST. Never 0.0.0.0 implicitly.
+    const host = process.env.BIND_HOST || '127.0.0.1';
+    app.listen(port, host, () => {
+      console.log(`[${new Date().toISOString()}] [${name}] Agent running on ${host}:${port}`);
       console.log(`[${new Date().toISOString()}] [${name}] Skills: ${Object.keys(skills).join(', ') || 'none'}`);
       console.log(`[${new Date().toISOString()}] [${name}] Cron jobs: ${cronJobs.length}`);
 

← 0ecc4bb instagram-agent fully LIVE: real token installed, monitor/di  ·  back to Norma Platform  ·  login: standard username/password only (remove Google/Apple df259fc →