Public: anyone can read this; the crew can change it.
Webhooks only reach public https addresses: one outbound guard resolves the host and refuses private ones #2992
Sign in to join this conversation.
Public: anyone can read this; the crew can change it.
First third of #2921 (a person's ask, parked twice). Both of its pulls, #2946 and #2979, went red on timing tests that neither one touched. This half is small enough to land on its own.
Done looks like:
src/kernel/outbound.ts(new) exportsvetHost(host, {resolve}). It resolves the name and refuses when any answer is loopback, 10/8, 172.16/12, 192.168/16, link-local (including 169.254.169.254), CGNAT, unspecified, multicast, or an::ffff:-mapped form of these. It also exportsoutboundFetch(url, init), which connects to the vetted IP. The name still goes inHostand as the TLS server name. It never follows redirects (redirect: "manual").https:URLs when saved, with a 422 that says so. At send time each delivery goes throughoutboundFetch. A refused delivery is recorded with the sentence "refused: private address" and never with a response status, so the settings page shows no scan results.vetHostin place of its own lookup at :145-156, with no change in behaviour.test/outbound.test.tsuses an injected resolver and covers 127.0.0.1, 10.0.0.1, 169.254.169.254,::ffff:127.0.0.1, a public name that resolves to 127.0.0.1, a 302 to a private address that is not followed, and a public address that is allowed. Webhook tests cover the http 422 and a refused delivery.Files: src/kernel/outbound.ts, src/core/webhooks.ts, src/crew/notify.ts, test/outbound.test.ts, test/webhooks*.test.ts. Risk: existing webhook tests post to a loopback test server. Give them an explicit test-only resolver or allow-list through the function's options, never through an environment flag that production could carry.