Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolved ssrf vulnerability #2657

Closed
wants to merge 12 commits into from
57 changes: 42 additions & 15 deletions website/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,28 +156,37 @@
def add_domain_to_company(request):
if request.method == "POST":
domain = request.POST.get("domain")
domain = Domain.objects.get(id=domain)
try:
domain = Domain.objects.get(id=domain)
except Domain.DoesNotExist:
return HttpResponseBadRequest("Invalid domain ID")
company_name = request.POST.get("company")
company = Company.objects.filter(name=company_name).first()

if not company:
response = requests.get(domain.url)
soup = BeautifulSoup(response.text, "html.parser")
if company_name in soup.get_text():
company = Company.objects.create(name=company_name)
domain.company = company
domain.save()
messages.success(request, "Organization added successfully")
# back to the domain detail page
return redirect("domain", slug=domain.url)
try:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very basic check for company name in the response body. Let's at least check that the request isn't being redirected to another location (status code 200 might work)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made the changes, plz do check if this satisfies the requirements. Thank you.

response = requests.get(domain.url, allow_redirects=False)

Check failure

Code scanning / CodeQL

Full server-side request forgery Critical

The full URL of this request depends on a
user-provided value
.
if response.status_code == 200:
soup = BeautifulSoup(response.text, "html.parser")
else:
messages.error(request, "Organization not found in the domain")
return redirect("domain", slug=domain.url)
else:
messages.error(
request,
f"Unexpected status code: {response.status_code}. The URL might be redirecting.",
)
return redirect("index")
except requests.RequestException as e:
messages.error(request, f"Failed to fetch URL: {e}")
return redirect("index")

if company_name in soup.get_text():
company = Company.objects.filter(name=company_name).first()
if not company:
company = Company.objects.create(name=company_name)
domain.company = company
domain.save()
messages.success(request, "Organization added successfully")
# back to the domain detail page
return redirect("domain", slug=domain.url)
else:
messages.error(request, "Organization not found in the domain")
return redirect("domain", slug=domain.url)
else:
return redirect("index")
Expand Down Expand Up @@ -3348,6 +3357,21 @@
return render(request, self.template_name, context)


def is_valid_url(url):
try:
parsed_url = urlparse(url)
if parsed_url.scheme not in {"http", "https"}:
return False
if re.match(
r"^(localhost|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2[0-9]|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})$",
parsed_url.hostname,
):
return False
return True
except Exception as e:
return False


@login_required(login_url="/accounts/login")
def add_or_update_domain(request):
if request.method == "POST":
Expand All @@ -3365,6 +3389,9 @@
domain.logo = request.FILES["logo"]
except:
pass
if not is_valid_url(request.POST["url"]):
return HttpResponseBadRequest("Invalid or Restricted URL")
domain.url = request.POST["url"]
domain.save()
return HttpResponse("Domain Updated")
except:
Expand Down
Loading