Skip to content

fix(webhook-server): default-bind to loopback instead of 0.0.0.0#2547

Closed
smith-vosburg wants to merge 1 commit into
nanocoai:mainfrom
vosburg-auto:upstream/fix/webhook-loopback-bind
Closed

fix(webhook-server): default-bind to loopback instead of 0.0.0.0#2547
smith-vosburg wants to merge 1 commit into
nanocoai:mainfrom
vosburg-auto:upstream/fix/webhook-loopback-bind

Conversation

@smith-vosburg
Copy link
Copy Markdown

Summary

  • Extract resolveListenConfig(env) so the webhook listen address is environment-driven and unit-testable.
  • Default bind to 127.0.0.1 so the webhook port (default 3000) is not exposed to the LAN. WEBHOOK_BIND=0.0.0.0 (or a specific interface IP) opts back into external exposure — typically a reverse proxy in front is preferable.
  • Use the helper in the server.listen call and include bind in the startup log line.
  • Add src/webhook-server.test.ts covering the loopback default, port + bind env overrides, the empty-string fallback, a specific-interface bind, and combined env vars.

Why

server.listen(port, '0.0.0.0', ...) at src/webhook-server.ts:121 binds the webhook to all interfaces. The webhook handles inbound callbacks for any adapter that registers via registerWebhookAdapter (Telegram, Slack via Chat SDK proxy, etc.). There's no auth at the HTTP layer — the adapter handlers trust the request shape — so anything on the LAN that can reach the host port can hit the webhook routes directly.

Defaulting to loopback closes that exposure for installs where the bot doesn't need to receive callbacks from outside the box. Installs that do need external callbacks (a real Telegram webhook from api.telegram.org, or a Slack event-subscription URL) will typically front the webhook with a reverse proxy / tunnel anyway; for the rare cases where you want the bot to listen on a LAN IP directly, WEBHOOK_BIND=<ip> (or 0.0.0.0) preserves the prior behavior.

Compatibility

This changes the default listen address from 0.0.0.0 to 127.0.0.1. For most installs (where Telegram polling is used, or a reverse proxy fronts the webhook) this is transparent. Installs that relied on direct LAN access to the webhook port need either:

  • A reverse proxy fronting it (recommended), or
  • WEBHOOK_BIND=0.0.0.0 set explicitly (preserves prior behavior).

Test plan

  • pnpm run build — clean
  • pnpm test src/webhook-server.test.ts — 6/6 pass; full suite 334/334 pass
  • Manual: with no env vars set, start the host and verify ss -ltn shows 127.0.0.1:3000 (not 0.0.0.0:3000)
  • Manual: set WEBHOOK_BIND=0.0.0.0, restart, verify the listen address goes back to all-interfaces

🤖 Generated with Claude Code

Extract resolveListenConfig() so the bind address is environment-driven
and unit-testable. Default to 127.0.0.1 so the webhook port is not
exposed to the LAN; set WEBHOOK_BIND=0.0.0.0 (or a specific interface
IP) to opt back into external exposure.

The existing webhook-server.test.ts imported resolveListenConfig from
the production module, but the symbol had never been extracted — the
test was effectively dead. This commit lands the missing refactor and
extends the test with the empty-string fallback, specific-interface,
and combined-env-var cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@smith-vosburg
Copy link
Copy Markdown
Author

Superseded — duplicate of #2546 (byte-identical content, opened earlier today by the same fork). Closing this one; track #2546 instead.

@smith-vosburg smith-vosburg deleted the upstream/fix/webhook-loopback-bind branch May 19, 2026 00:31
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