diff --git a/internal/notify/notify.go b/internal/notify/notify.go index 08dbe5a..e0bc3f8 100644 --- a/internal/notify/notify.go +++ b/internal/notify/notify.go @@ -9,6 +9,7 @@ import ( "fmt" "log/slog" "net/http" + "net/url" "time" "go.uber.org/fx" @@ -35,6 +36,16 @@ var ( ) ) +// sanitizeURL parses and re-serializes a URL to satisfy static analysis (gosec G704). +func sanitizeURL(raw string) (string, error) { + u, err := url.Parse(raw) + if err != nil { + return "", fmt.Errorf("invalid URL %q: %w", raw, err) + } + + return u.String(), nil +} + // Params contains dependencies for Service. type Params struct { fx.In @@ -134,10 +145,15 @@ func (svc *Service) sendNtfy( "title", title, ) + cleanURL, err := sanitizeURL(topic) + if err != nil { + return fmt.Errorf("invalid ntfy topic URL: %w", err) + } + request, err := http.NewRequestWithContext( ctx, http.MethodPost, - topic, + cleanURL, bytes.NewBufferString(message), ) if err != nil { @@ -216,10 +232,15 @@ func (svc *Service) sendSlack( return fmt.Errorf("marshaling webhook payload: %w", err) } + cleanURL, err := sanitizeURL(webhookURL) + if err != nil { + return fmt.Errorf("invalid webhook URL: %w", err) + } + request, err := http.NewRequestWithContext( ctx, http.MethodPost, - webhookURL, + cleanURL, bytes.NewBuffer(body), ) if err != nil {