decolua/9router · error
EACCES
EACCES
Error message
Permission denied for port ${LOCAL_PORT} What it means
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.
Source
Thrown at src/mitm/server.js:386
});
log(`Killed ${pidList.length} process(es) on port ${port}`);
} catch (e) {
if (e.status !== 1) throw e;
}
}
try {
killPort(LOCAL_PORT);
} catch (e) {
err(`Cannot kill process on port ${LOCAL_PORT}: ${e.message}`);
process.exit(1);
}
server.listen(LOCAL_PORT, () => log(`🚀 Server ready on :${LOCAL_PORT}`));
server.on("error", (e) => {
if (e.code === "EADDRINUSE") err(`Port ${LOCAL_PORT} already in use`);
else if (e.code === "EACCES") err(`Permission denied for port ${LOCAL_PORT}`);
else err(e.message);
process.exit(1);
});
const { removeAllDNSEntriesSync } = require("./dns/dnsConfig");
let isShuttingDown = false;
const shutdown = () => {
if (isShuttingDown) return;
isShuttingDown = true;
// Strip tool hosts from /etc/hosts so other apps aren't broken after exit
removeAllDNSEntriesSync();
const forceExit = setTimeout(() => process.exit(0), 1500);
server.close(() => { clearTimeout(forceExit); process.exit(0); });
};
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);
if (process.platform === "win32") process.on("SIGBREAK", shutdown);
View on GitHub (pinned to 90b52e06ff)
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.
Example fix
// before LOCAL_PORT=443 → EACCES (unprivileged) // after LOCAL_PORT=20129 # and map the upstream host to 127.0.0.1:20129 via the mitm DNS config
Defensive patterns
Strategy: validation
Validate before calling
const LOCAL_PORT = Number(process.env.MITM_LOCAL_PORT || 20129);
if (LOCAL_PORT < 1024 && process.getuid && process.getuid() !== 0) {
console.error(`Port ${LOCAL_PORT} is privileged — use a port > 1024 or grant cap_net_bind_service`);
process.exit(1);
} Type guard
function isPrivilegedPort(p) { return Number.isInteger(p) && p > 0 && p < 1024; } Try / catch
server.on('error', (e) => {
if (e.code === 'EACCES') {
err(`Permission denied for port ${LOCAL_PORT} — use an unprivileged port (>1024)`);
process.exit(1);
}
}); Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Sudo password required to install Root CA certificate
- Sudo password required to trust certificate
- Machine ID is required for Cursor API
- http2 module not available
- HTTP/2 is required for Cursor AgentService (endpoint is h2-o
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/f86b09b868e0ae9e.
Report an issue: GitHub.