mirror of
https://github.com/abhinavxd/libredesk.git
synced 2026-10-22 20:45:23 +00:00
9566dcbf4d
Move the webhook SSRF guard into a shared internal/ssrf package and wire it into every place the server fetches an admin-set URL: webhooks, OIDC discovery, the AI provider base URL, and custom AI tool calls. Add a global [ssrf] config block, off by default with an allowed_cidrs bypass, so single-tenant self-hosters keep reaching internal hosts while multi-tenant or hosted deploys can turn it on. The old [webhook] allowed_hosts key is still read for backward compat and folds into the guard.
37 lines
1.2 KiB
Go
37 lines
1.2 KiB
Go
// Package ssrf builds the shared outbound-request guard used across every
|
|
// admin-configured outbound URL (webhooks, OIDC discovery, AI provider and
|
|
// custom tool calls). It is off by default and meant to be enabled on
|
|
// multi-tenant/hosted deployments where those URLs come from untrusted tenants.
|
|
package ssrf
|
|
|
|
import (
|
|
"net/netip"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/abhinavxd/ssrfguard"
|
|
"github.com/zerodha/logf"
|
|
)
|
|
|
|
// Control matches net.Dialer.Control. A nil value means no guarding.
|
|
type Control = func(network, address string, c syscall.RawConn) error
|
|
|
|
// NewControl returns a net.Dialer.Control that blocks connections to private and
|
|
// reserved IP ranges, or nil when disabled. allowedCIDRs carve out exceptions
|
|
// (e.g. an operator's own internal host) that stay reachable while enabled.
|
|
func NewControl(enabled bool, allowedCIDRs []string, lo *logf.Logger) Control {
|
|
if !enabled {
|
|
return nil
|
|
}
|
|
var allowed []netip.Prefix
|
|
for _, c := range allowedCIDRs {
|
|
prefix, err := netip.ParsePrefix(strings.TrimSpace(c))
|
|
if err != nil {
|
|
lo.Warn("ignoring invalid ssrf `allowed_cidrs` entry", "entry", c, "error", err)
|
|
continue
|
|
}
|
|
allowed = append(allowed, prefix)
|
|
}
|
|
return ssrfguard.New(allowed...).Control
|
|
}
|