🛡️ Sentinel: [HIGH] Fix Server-Side Request Forgery in webhooks

Adds validation to webhook URLs before attempting to deliver them to prevent
SSRF attacks targeting private IP ranges, local host, and cloud metadata endpoints.
Validates URL schema, hostname, and applies `is_private_ip()`. Also resolved ruff linting
errors. Tests have been expanded to ensure validation covers all cases.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-05-17 15:04:09 +00:00
parent 58b14ae769
commit 5b41d32f90
7 changed files with 146 additions and 46 deletions
+26
View File
@@ -12,6 +12,7 @@ import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from typing import Any
from urllib.parse import urlparse
import httpx
@@ -128,6 +129,31 @@ def _send_webhook_notification(target_config: dict[str, Any], event_type: str, t
logger.warning("Webhook notification target missing url")
return False
from app.utils.network import is_private_ip
parsed_url = urlparse(url)
if parsed_url.scheme not in ("http", "https"):
logger.warning("Webhook notification to %s blocked: Invalid scheme %s", url, parsed_url.scheme)
return False
hostname = parsed_url.hostname
if not hostname:
logger.warning("Webhook notification to %s blocked: No hostname", url)
return False
if is_private_ip(hostname):
logger.warning("Webhook notification to %s blocked: Private IP", url)
return False
metadata_endpoints = [
"169.254.169.254", # AWS, Azure, GCP metadata
"metadata.google.internal", # GCP
"169.254.169.253", # AWS link-local
]
if hostname in metadata_endpoints:
logger.warning("Webhook notification to %s blocked: Metadata endpoint", url)
return False
payload = {
"event": event_type,
"title": title,