33# See the LICENSE file for details.
44
55# Python imports
6+ import os
67import socket
78import ipaddress
89from urllib .parse import urlparse
1516from plane .db .models import Webhook , WebhookLog
1617from plane .db .models .webhook import validate_domain , validate_schema
1718
19+ ENABLE_WEBHOOK_SSRF_PROTECTION = os .environ .get ("ENABLE_WEBHOOK_SSRF_PROTECTION" , "1" ) != "0"
20+
1821
1922class WebhookSerializer (DynamicBaseSerializer ):
2023 url = serializers .URLField (validators = [validate_schema , validate_domain ])
@@ -36,10 +39,11 @@ def create(self, validated_data):
3639 if not ip_addresses :
3740 raise serializers .ValidationError ({"url" : "No IP addresses found for the hostname." })
3841
39- for addr in ip_addresses :
40- ip = ipaddress .ip_address (addr [4 ][0 ])
41- if ip .is_private or ip .is_loopback or ip .is_reserved or ip .is_link_local :
42- raise serializers .ValidationError ({"url" : "URL resolves to a blocked IP address." })
42+ if ENABLE_WEBHOOK_SSRF_PROTECTION :
43+ for addr in ip_addresses :
44+ ip = ipaddress .ip_address (addr [4 ][0 ])
45+ if ip .is_private or ip .is_loopback or ip .is_reserved or ip .is_link_local :
46+ raise serializers .ValidationError ({"url" : "URL resolves to a blocked IP address." })
4347
4448 # Additional validation for multiple request domains and their subdomains
4549 request = self .context .get ("request" )
@@ -71,10 +75,11 @@ def update(self, instance, validated_data):
7175 if not ip_addresses :
7276 raise serializers .ValidationError ({"url" : "No IP addresses found for the hostname." })
7377
74- for addr in ip_addresses :
75- ip = ipaddress .ip_address (addr [4 ][0 ])
76- if ip .is_private or ip .is_loopback or ip .is_reserved or ip .is_link_local :
77- raise serializers .ValidationError ({"url" : "URL resolves to a blocked IP address." })
78+ if ENABLE_WEBHOOK_SSRF_PROTECTION :
79+ for addr in ip_addresses :
80+ ip = ipaddress .ip_address (addr [4 ][0 ])
81+ if ip .is_private or ip .is_loopback or ip .is_reserved or ip .is_link_local :
82+ raise serializers .ValidationError ({"url" : "URL resolves to a blocked IP address." })
7883
7984 # Additional validation for multiple request domains and their subdomains
8085 request = self .context .get ("request" )
0 commit comments