Unverified Commit cd5816c4 authored by memoclaw's avatar memoclaw Committed by GitHub

feat: add --allow-private-webhooks flag to bypass SSRF protection (#5694)

Co-authored-by: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 851e090f
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"github.com/usememos/memos/internal/profile" "github.com/usememos/memos/internal/profile"
"github.com/usememos/memos/internal/version" "github.com/usememos/memos/internal/version"
"github.com/usememos/memos/plugin/webhook"
"github.com/usememos/memos/server" "github.com/usememos/memos/server"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
"github.com/usememos/memos/store/db" "github.com/usememos/memos/store/db"
...@@ -36,6 +37,7 @@ var ( ...@@ -36,6 +37,7 @@ var (
InstanceURL: viper.GetString("instance-url"), InstanceURL: viper.GetString("instance-url"),
} }
instanceProfile.Version = version.GetCurrentVersion() instanceProfile.Version = version.GetCurrentVersion()
webhook.AllowPrivateIPs = viper.GetBool("allow-private-webhooks")
if err := instanceProfile.Validate(); err != nil { if err := instanceProfile.Validate(); err != nil {
slog.Error("failed to validate profile", "error", err) slog.Error("failed to validate profile", "error", err)
...@@ -105,6 +107,7 @@ func init() { ...@@ -105,6 +107,7 @@ func init() {
rootCmd.PersistentFlags().String("driver", "sqlite", "database driver") rootCmd.PersistentFlags().String("driver", "sqlite", "database driver")
rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)") rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)")
rootCmd.PersistentFlags().String("instance-url", "", "the url of your memos instance") rootCmd.PersistentFlags().String("instance-url", "", "the url of your memos instance")
rootCmd.PersistentFlags().Bool("allow-private-webhooks", false, "allow webhook URLs to resolve to private/reserved IP addresses")
if err := viper.BindPFlag("demo", rootCmd.PersistentFlags().Lookup("demo")); err != nil { if err := viper.BindPFlag("demo", rootCmd.PersistentFlags().Lookup("demo")); err != nil {
panic(err) panic(err)
...@@ -130,6 +133,9 @@ func init() { ...@@ -130,6 +133,9 @@ func init() {
if err := viper.BindPFlag("instance-url", rootCmd.PersistentFlags().Lookup("instance-url")); err != nil { if err := viper.BindPFlag("instance-url", rootCmd.PersistentFlags().Lookup("instance-url")); err != nil {
panic(err) panic(err)
} }
if err := viper.BindPFlag("allow-private-webhooks", rootCmd.PersistentFlags().Lookup("allow-private-webhooks")); err != nil {
panic(err)
}
viper.SetEnvPrefix("memos") viper.SetEnvPrefix("memos")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
......
...@@ -35,8 +35,16 @@ func init() { ...@@ -35,8 +35,16 @@ func init() {
} }
} }
// AllowPrivateIPs controls whether webhook URLs may resolve to reserved/private
// IP addresses. When true, the SSRF protection is disabled. This is useful for
// self-hosted deployments where webhooks target services on the local network.
var AllowPrivateIPs bool
// isReservedIP reports whether ip falls within any reserved/private range. // isReservedIP reports whether ip falls within any reserved/private range.
func isReservedIP(ip net.IP) bool { func isReservedIP(ip net.IP) bool {
if AllowPrivateIPs {
return false
}
for _, network := range reservedNetworks { for _, network := range reservedNetworks {
if network.Contains(ip) { if network.Contains(ip) {
return true return true
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment