fix(security): SSRF protection for alarm webhooks (FLAW-05)

Discord and custom webhook URLs are checked when saved and before every
call: https only, Discord URLs must point to discord.com. A guarded HTTP
client resolves hosts itself and connects only to allowed IPs; localhost,
link-local and cloud metadata are always blocked, LAN ranges (incl.
Tailscale CGNAT) and plain http only with the new admin switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 07:37:39 +01:00
1 parent 4cdbcbd6b5
commit 62463bc6fd
8 files changed
+288 -16

No files matched your search

+11 -2
View File
@@ -490,7 +490,8 @@ func (s *Store) migrate() error {
('smtp_pass', ''),
('smtp_from', ''),
('smtp_tls', 'true'),
('smtp_skip_verify', 'false')`)
('smtp_skip_verify', 'false'),
('allow_private_webhooks', 'false')`)
// Clean up legacy roles in team_members and users
_, _ = s.db.Exec(`UPDATE team_members SET role = 'admin' WHERE role IN ('team_admin', 'owner')`)
@@ -5090,6 +5091,8 @@ func (s *Store) GetSystemSettings() (*domain.SystemSettings, error) {
settings.SMTPTLS = (v != "false" && v != "0")
case "smtp_skip_verify":
settings.SMTPSkipVerify = v == "true"
case "allow_private_webhooks":
settings.AllowPrivateWebhooks = v == "true"
}
}
}
@@ -5109,6 +5112,10 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
if settings.SMTPSkipVerify {
skipVerifyStr = "true"
}
privateHooksStr := "false"
if settings.AllowPrivateWebhooks {
privateHooksStr = "true"
}
if settings.SMTPPort == "" {
settings.SMTPPort = "587"
}
@@ -5126,7 +5133,8 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
('smtp_pass', ?),
('smtp_from', ?),
('smtp_tls', ?),
('smtp_skip_verify', ?)
('smtp_skip_verify', ?),
('allow_private_webhooks', ?)
ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
settings.SharingMode,
regStr,
@@ -5138,6 +5146,7 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
strings.TrimSpace(settings.SMTPFrom),
tlsStr,
skipVerifyStr,
privateHooksStr,
)
return err
}