Skip to content

V23: Refuse to serve an unprotected agent on a public interface - #697

Merged
LinuxDevil merged 2 commits into
mainfrom
v23-refuse-public-unprotected
Oct 20, 2026
Merged

LinuxDevil merged 2 commits into
mainfrom
v23-refuse-public-unprotected

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

Fixes audit finding SEC-2 (Vercel competitor audit, 2026-10-19).

Behavior change: the built node-server (and so the Docker image, which sets HOST=0.0.0.0) now refuses to start on a non-loopback host when no route auth is configured (no LOUSHO_API_TOKEN, no build token, no auth.ts). It exits non-zero with LOUSHO_SERVER_UNPROTECTED. Opt out with LOUSHO_ALLOW_PUBLIC=1, which keeps the old open-with-warning behaviour. Loopback hosts (localhost, 127.x.x.x, ::1) are unchanged.

What was wrong

HOST=0.0.0.0 LOUSHO_API_TOKEN= node dist/server.js only logged warning: no LOUSHO_API_TOKEN set, so anyone who can reach 0.0.0.0 can use this agent. and then served POST /chat to anyone. The Docker image binds 0.0.0.0 by default, so a docker-on-VPS deploy without a token was wide open.

What changed

  • src/deploy/nodeServer.ts: new checkServerExposure(host, authenticated, env). It uses the same authenticated flag that createDeployedServer() already derives from the token, build token or auth list (auth.ts), which is also what gates channel routes since V1: Gate unverified channel routes behind LOUSHO_API_TOKEN in the built server #676. Loopback means localhost, ::1/[::1] or 127.0.0.0/8. With no auth on any other host it throws SDKError LOUSHO_SERVER_UNPROTECTED unless LOUSHO_ALLOW_PUBLIC is 1/true; in that case it returns the existing warning text.
  • Generated server.ts (src/deploy/adapters/node-server.ts): calls the check before listen. A refusal goes through the existing failed to start path and exits with code 1. The hard-coded LOOPBACK list is gone. runtime.ts exports the check.
  • LOUSHO_SERVER_UNPROTECTED added to src/utils/errorCodes.ts and to docs/errors.md (heading plus the index row).
  • Docker adapter: the Dockerfile comment explains the token requirement. describe() now prints docker run -p 3000:3000 -e LOUSHO_API_TOKEN=<token> lousho-agent.
  • Docs: deployment.md (Auth, node-server and docker sections, plus the targets table now pass the token), hostinger-vps.md, upgrading.md (row in "HTTP routes, servers and channels" with opt-out LOUSHO_ALLOW_PUBLIC=1). Regenerated llms files. examples/hostinger-deploy already requires and passes LOUSHO_API_TOKEN, so it is unchanged.

Tests

  • New src/deploy/nodeServerPublic.test.ts (16 cases):
    • 0.0.0.0, ::, a LAN IP or a hostname with no auth is rejected with LOUSHO_SERVER_UNPROTECTED, and the message names all four fixes.
    • The server starts when LOUSHO_API_TOKEN is set, or when there is an auth list and no token.
    • LOUSHO_ALLOW_PUBLIC=1/true returns the warning. =0 is not an opt-out.
    • 127.0.0.1, 127.1.2.3, localhost, ::1 and [::1] start with no auth and no warning.
  • node-server.test.ts (end to end against the built dist/server.js):
    • --host=0.0.0.0 with no token exits non-zero, and stderr contains LOUSHO_SERVER_UNPROTECTED.
    • With LOUSHO_ALLOW_PUBLIC=1 it starts and prints the warning.
    • The --host binding test now sets a token.
  • docker.docker.test.ts passes -e LOUSHO_ALLOW_PUBLIC=1, because those tests call /chat without a token. docker.test.ts covers the new describe() string.
  • Ran: npx tsc --noEmit, npm run typecheck:tests and npm run lint all clean. npm run test:coverage passed 413 files / 6106 tests, and npm run fallow exited 0. npm run test:docker against a real daemon passed 2 tests. docs:llms:check is clean.

Changelog: The built node-server and Docker image refuse to start on a non-loopback host with no auth (LOUSHO_SERVER_UNPROTECTED); set LOUSHO_API_TOKEN, add auth.ts, bind to 127.0.0.1, or set LOUSHO_ALLOW_PUBLIC=1.

🤖 Generated with Claude Code

The built node-server (and the Docker image, which binds 0.0.0.0) now
exits with LOUSHO_SERVER_UNPROTECTED when it would listen on a
non-loopback host with no route auth (no LOUSHO_API_TOKEN, build token
or auth.ts). LOUSHO_ALLOW_PUBLIC=1 keeps the old open-with-warning
behaviour. Loopback hosts are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LinuxDevil
LinuxDevil force-pushed the v23-refuse-public-unprotected branch from 9e9aa14 to 2a26eb2 Compare October 20, 2026 07:18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LinuxDevil
LinuxDevil merged commit 7481642 into main Oct 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant