{"record":{"id":"f86b09b868e0ae9e","repo":"decolua/9router","slug":"eacces","errorCode":"EACCES","errorMessage":"Permission denied for port ${LOCAL_PORT}","messagePattern":"Permission denied for port (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/mitm/server.js","lineNumber":386,"sourceCode":"    });\n    log(`Killed ${pidList.length} process(es) on port ${port}`);\n  } catch (e) {\n    if (e.status !== 1) throw e;\n  }\n}\n\ntry {\n  killPort(LOCAL_PORT);\n} catch (e) {\n  err(`Cannot kill process on port ${LOCAL_PORT}: ${e.message}`);\n  process.exit(1);\n}\n\nserver.listen(LOCAL_PORT, () => log(`🚀 Server ready on :${LOCAL_PORT}`));\n\nserver.on(\"error\", (e) => {\n  if (e.code === \"EADDRINUSE\") err(`Port ${LOCAL_PORT} already in use`);\n  else if (e.code === \"EACCES\") err(`Permission denied for port ${LOCAL_PORT}`);\n  else err(e.message);\n  process.exit(1);\n});\n\nconst { removeAllDNSEntriesSync } = require(\"./dns/dnsConfig\");\nlet isShuttingDown = false;\nconst shutdown = () => {\n  if (isShuttingDown) return;\n  isShuttingDown = true;\n  // Strip tool hosts from /etc/hosts so other apps aren't broken after exit\n  removeAllDNSEntriesSync();\n  const forceExit = setTimeout(() => process.exit(0), 1500);\n  server.close(() => { clearTimeout(forceExit); process.exit(0); });\n};\nprocess.on(\"SIGTERM\", shutdown);\nprocess.on(\"SIGINT\", shutdown);\nif (process.platform === \"win32\") process.on(\"SIGBREAK\", shutdown);\n","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/mitm/server.js#L368-L404","documentation":"The MITM proxy cannot bind LOCAL_PORT because the OS denies the bind (errno EACCES) — the server logs 'Permission denied for port <LOCAL_PORT>' and exits with code 1.","triggerScenarios":"server.listen(LOCAL_PORT) with LOCAL_PORT < 1024 on Linux/macOS without root/CAP_NET_BIND_SERVICE, or on a port blocked by local security policy (SELinux, sandboxed environment).","commonSituations":"Configured the MITM port to 80/443 to impersonate the real upstream without elevated privileges; running inside a container/sandbox that forbids binding privileged ports; firewall policy blocking the bind.","solutions":["Set LOCAL_PORT to an unprivileged port (>1024, e.g. 20129) and point the tool's proxy/DNS override at it instead of 443.","Grant the Node binary the capability: sudo setcap 'cap_net_bind_service=+ep' $(which node) (Linux).","Run with elevated privileges only if acceptable (sudo) — not recommended for a local proxy.","Check SELinux/AppArmor/sandbox policies if the port is unprivileged but still denied."],"exampleFix":"// before\nLOCAL_PORT=443 → EACCES (unprivileged)\n// after\nLOCAL_PORT=20129  # and map the upstream host to 127.0.0.1:20129 via the mitm DNS config","handlingStrategy":"validation","validationCode":"const LOCAL_PORT = Number(process.env.MITM_LOCAL_PORT || 20129);\nif (LOCAL_PORT < 1024 && process.getuid && process.getuid() !== 0) {\n  console.error(`Port ${LOCAL_PORT} is privileged — use a port > 1024 or grant cap_net_bind_service`);\n  process.exit(1);\n}","typeGuard":"function isPrivilegedPort(p) { return Number.isInteger(p) && p > 0 && p < 1024; }","tryCatchPattern":"server.on('error', (e) => {\n  if (e.code === 'EACCES') {\n    err(`Permission denied for port ${LOCAL_PORT} — use an unprivileged port (>1024)`);\n    process.exit(1);\n  }\n});","preventionTips":["Always configure the MITM on an unprivileged port (>1024).","If port 443 is required, grant cap_net_bind_service to the Node binary instead of running as root.","Check container/sandbox port policies before deploying the proxy.","Document the chosen port and point tool/DNS overrides at it consistently."],"tags":["eacces","privileged-port","mitm","permissions"],"backgroundTag":"port-permission-denied","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}