From 316fbf2f5f54f040f3df3f75b38988253bde242e Mon Sep 17 00:00:00 2001 From: David Roe Date: Wed, 22 May 2024 15:52:43 +0100 Subject: [PATCH] feat(python): add cwe-601 open redirect rule (#416) --- rules/python/django/open_redirect.yml | 68 +++++++++++++++++++ tests/python/django/open_redirect/test.js | 20 ++++++ .../django/open_redirect/testdata/main.py | 18 +++++ 3 files changed, 106 insertions(+) create mode 100644 rules/python/django/open_redirect.yml create mode 100644 tests/python/django/open_redirect/test.js create mode 100644 tests/python/django/open_redirect/testdata/main.py diff --git a/rules/python/django/open_redirect.yml b/rules/python/django/open_redirect.yml new file mode 100644 index 00000000..eea976d7 --- /dev/null +++ b/rules/python/django/open_redirect.yml @@ -0,0 +1,68 @@ +imports: + - python_shared_common_user_input + - python_shared_lang_import2 +patterns: + - pattern: $($$<...>) + filters: + - variable: FUNCTION + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [django] + - variable: MODULE2 + values: [http] + - variable: NAME + values: + - HttpResponseRedirect + - HttpResponsePermanentRedirect + - variable: USER_INPUT + detection: python_shared_common_user_input + scope: result + - pattern: $($$<...>) + filters: + - variable: FUNCTION + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [django] + - variable: MODULE2 + values: [shortcuts] + - variable: NAME + values: [redirect] + - variable: USER_INPUT + detection: python_shared_common_user_input + scope: result +languages: + - python +severity: medium +metadata: + description: "Unsanitized user input in redirect" + remediation_message: |- + ## Description + + Using unsanitized user input to perform redirects can make your application vulnerable to phishing attacks. This occurs when user input is directly used to determine the destination of a redirect without proper validation or sanitization, allowing attackers to redirect users to malicious sites, potentially compromising their security. + + ## Remediations + + - **Do not** use unsanitized user input when constructing URLs for redirects. Directly incorporating user input without validation can lead to phishing attacks and malicious site redirection. + - **Do** validate user input by employing a safe list or a mapping strategy for constructing URLs. This ensures that the redirection is to a known, safe location. + ```python + paths = dict( + 1="/planes", + 2="/trains", + 3="/automobiles" + ) + + transport = request.GET["transport"] + redirect(paths[transport]); + ``` + + ## References + + - [OWASP Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) + cwe_id: + - 601 + id: python_django_open_redirect + documentation_url: https://docs.bearer.com/reference/rules/python_django_open_redirect diff --git a/tests/python/django/open_redirect/test.js b/tests/python/django/open_redirect/test.js new file mode 100644 index 00000000..6d5a83dc --- /dev/null +++ b/tests/python/django/open_redirect/test.js @@ -0,0 +1,20 @@ +const { + createNewInvoker, + getEnvironment, +} = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("open_redirect", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/django/open_redirect/testdata/main.py b/tests/python/django/open_redirect/testdata/main.py new file mode 100644 index 00000000..9e678f05 --- /dev/null +++ b/tests/python/django/open_redirect/testdata/main.py @@ -0,0 +1,18 @@ +user_input = form.cleaned_data["path"] + +from django.shortcuts import redirect + +redirect("ok", False) +# bearer:expected python_django_open_redirect +redirect(user_input, False) + + +from django.http import HttpResponsePermanentRedirect, HttpResponseRedirect + +HttpResponseRedirect("ok", headers={}) +# bearer:expected python_django_open_redirect +HttpResponseRedirect(user_input, headers={}) + +HttpResponsePermanentRedirect("ok", headers={}) +# bearer:expected python_django_open_redirect +HttpResponsePermanentRedirect(user_input, headers={}) \ No newline at end of file