From 934dfebab5d6b84b217ee7df72892e9f504b54d0 Mon Sep 17 00:00:00 2001 From: wtkm11 Date: Thu, 30 Apr 2020 21:48:45 -0400 Subject: [PATCH 1/9] Detect misuse of `psycopg2.sql.SQL` composable Add a plugin test to detect when something other than a string literal is passed to the constructor of the `psycopg2.sql.SQL` composable object. Resolves: #412 --- README.rst | 1 + bandit/plugins/psycopg2_sql_injection.py | 40 ++++++++++++++++++++++++ examples/psycopg2_sql_injection.py | 4 +++ setup.cfg | 3 ++ 4 files changed, 48 insertions(+) create mode 100644 bandit/plugins/psycopg2_sql_injection.py create mode 100644 examples/psycopg2_sql_injection.py diff --git a/README.rst b/README.rst index 9d685d9e2..c0f14b3b0 100644 --- a/README.rst +++ b/README.rst @@ -254,6 +254,7 @@ Usage:: B609 linux_commands_wildcard_injection B610 django_extra_used B611 django_rawsql_used + B612 psycopg2_sql_injection B701 jinja2_autoescape_false B702 use_of_mako_templates B703 django_mark_safe diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py new file mode 100644 index 000000000..9f6a4f743 --- /dev/null +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- +# +# SPDX-License-Identifier: Apache-2.0 + +import ast + +import bandit +from bandit.core import test_properties as test + + +@test.checks('Call') +@test.test_id('B612') +def psycopg2_sql_injection(context): + """**B612: Potential SQL injection on psycopg2 raw SQL composable object ** + + The `psycopg2.sql.SQL` composable object should not be used to represent + variable identifiers or values that may be controlled by an attacker since + the argument that is passed to the `SQL` constructor is not escaped when + the SQL statement is composed. Instead, `SQL` should only be used to + represent constant strings. + + .. seealso:: + + - https://www.psycopg.org/docs/sql.html + + .. versionadded:: 1.6.2 + """ + if context.is_module_imported_like('psycopg2.sql'): + if context.call_function_name == 'SQL': + argument = context.node.args[0] + if not isinstance(argument, ast.Str): + return bandit.Issue( + severity=bandit.MEDIUM, + confidence=bandit.MEDIUM, + text=( + "Possible SQL injection vector through instantiation " + "of psycopg2.sql.SQL composable object on an argument " + "other than a string literal." + ) + ) diff --git a/examples/psycopg2_sql_injection.py b/examples/psycopg2_sql_injection.py new file mode 100644 index 000000000..82608c6b9 --- /dev/null +++ b/examples/psycopg2_sql_injection.py @@ -0,0 +1,4 @@ +from psycopg2 import sql + +table = 'users; drop table users; --' +sql.SQL('select * from {}').format(sql.SQL(table)) diff --git a/setup.cfg b/setup.cfg index f0ec29c01..12b0dc4ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -122,6 +122,9 @@ bandit.plugins = # bandit/plugins/ssh_no_host_key_verification.py ssh_no_host_key_verification = bandit.plugins.ssh_no_host_key_verification:ssh_no_host_key_verification + # bandit/plugins/psycopg2_sql_injection.py + psycopg2_sql_injection = bandit.plugins.psycopg2_sql_injection:psycopg2_sql_injection + [build_sphinx] all_files = 1 build-dir = doc/build From 2b18f60eb349403e64cc9d1bb7beec53267a72fa Mon Sep 17 00:00:00 2001 From: wtkm11 Date: Mon, 4 May 2020 17:51:25 -0400 Subject: [PATCH 2/9] Add functional test for psycopg2 sql injection plugin test --- tests/functional/test_functional.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index e3b73702d..3debd6698 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -369,6 +369,14 @@ def test_popen_wrappers(self): } self.check_example('popen_wrappers.py', expect) + def test_psycopg2_sql_injection(self): + '''Test the `psycopg2` SQL injection example.''' + expect = { + 'SEVERITY': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 1, 'HIGH': 0}, + 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 1, 'HIGH': 0} + } + self.check_example('psycopg2_sql_injection.py', expect) + def test_random_module(self): '''Test for the `random` module.''' expect = { From 07004534d9a6dfc78a5c2e5727cb53e91387b451 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 20:09:29 -0700 Subject: [PATCH 3/9] Apply suggestions from code review --- README.rst | 1 - bandit/plugins/psycopg2_sql_injection.py | 12 +++++------- tests/functional/test_functional.py | 6 +++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 70acfb426..3a7149ce7 100644 --- a/README.rst +++ b/README.rst @@ -255,7 +255,6 @@ Usage:: B609 linux_commands_wildcard_injection B610 django_extra_used B611 django_rawsql_used - B612 psycopg2_sql_injection B701 jinja2_autoescape_false B702 use_of_mako_templates B703 django_mark_safe diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 9f6a4f743..f8167a869 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -1,5 +1,3 @@ -# -*- coding:utf-8 -*- -# # SPDX-License-Identifier: Apache-2.0 import ast @@ -8,8 +6,8 @@ from bandit.core import test_properties as test -@test.checks('Call') -@test.test_id('B612') +@test.checks("Call") +@test.test_id("B612") def psycopg2_sql_injection(context): """**B612: Potential SQL injection on psycopg2 raw SQL composable object ** @@ -23,10 +21,10 @@ def psycopg2_sql_injection(context): - https://www.psycopg.org/docs/sql.html - .. versionadded:: 1.6.2 + .. versionadded:: 1.7.5 """ - if context.is_module_imported_like('psycopg2.sql'): - if context.call_function_name == 'SQL': + if context.is_module_imported_like("psycopg2.sql"): + if context.call_function_name == "SQL": argument = context.node.args[0] if not isinstance(argument, ast.Str): return bandit.Issue( diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 9765ff52f..eb1bdebf2 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -372,10 +372,10 @@ def test_popen_wrappers(self): def test_psycopg2_sql_injection(self): '''Test the `psycopg2` SQL injection example.''' expect = { - 'SEVERITY': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 1, 'HIGH': 0}, - 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 1, 'HIGH': 0} + "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, + "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, } - self.check_example('psycopg2_sql_injection.py', expect) + self.check_example("psycopg2_sql_injection.py", expect) def test_random_module(self): '''Test for the `random` module.''' From a73cb4562c7514485574df9aeb8258e2c2452c16 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 20:12:27 -0700 Subject: [PATCH 4/9] Apply suggestions from code review --- bandit/plugins/psycopg2_sql_injection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index f8167a869..017949737 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -7,9 +7,9 @@ @test.checks("Call") -@test.test_id("B612") +@test.test_id("B613") def psycopg2_sql_injection(context): - """**B612: Potential SQL injection on psycopg2 raw SQL composable object ** + """**B613: Potential SQL injection on psycopg2 raw SQL composable object ** The `psycopg2.sql.SQL` composable object should not be used to represent variable identifiers or values that may be controlled by an attacker since From 54ce5d15b0a54f14edcf23df8538296349279b2f Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 20:16:11 -0700 Subject: [PATCH 5/9] Apply suggestions from code review --- bandit/plugins/psycopg2_sql_injection.py | 2 +- tests/functional/test_functional.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 017949737..04048a52b 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -34,5 +34,5 @@ def psycopg2_sql_injection(context): "Possible SQL injection vector through instantiation " "of psycopg2.sql.SQL composable object on an argument " "other than a string literal." - ) + ), ) diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index a23948418..17bd598be 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -394,7 +394,7 @@ def test_popen_wrappers(self): self.check_example("popen_wrappers.py", expect) def test_psycopg2_sql_injection(self): - '''Test the `psycopg2` SQL injection example.''' + """Test the `psycopg2` SQL injection example.""" expect = { "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, From e674fa27c102c0520c4484e2e370e443f19564cf Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 20:19:18 -0700 Subject: [PATCH 6/9] Update bandit/plugins/psycopg2_sql_injection.py --- bandit/plugins/psycopg2_sql_injection.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 04048a52b..40f479858 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -1,5 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 - import ast import bandit From 17ddf4708c4c72a4d65b04f81c151ccb1100b470 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 21:32:25 -0700 Subject: [PATCH 7/9] Update bandit/plugins/psycopg2_sql_injection.py --- bandit/plugins/psycopg2_sql_injection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 40f479858..887cb4967 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -29,6 +29,7 @@ def psycopg2_sql_injection(context): return bandit.Issue( severity=bandit.MEDIUM, confidence=bandit.MEDIUM, + cwe=issue.Cwe.SQL_INJECTION, text=( "Possible SQL injection vector through instantiation " "of psycopg2.sql.SQL composable object on an argument " From 84227c7533726892b75a0b9f2a0a0d30d248be68 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 11 Jul 2022 21:33:18 -0700 Subject: [PATCH 8/9] Update bandit/plugins/psycopg2_sql_injection.py --- bandit/plugins/psycopg2_sql_injection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 887cb4967..3312a23b9 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -2,6 +2,7 @@ import ast import bandit +from bandit.core import issue from bandit.core import test_properties as test From 9bbff0ac342774aa7293844cffc70f992be82608 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Sat, 8 Apr 2023 21:27:38 -0700 Subject: [PATCH 9/9] Apply suggestions from code review --- bandit/plugins/psycopg2_sql_injection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bandit/plugins/psycopg2_sql_injection.py b/bandit/plugins/psycopg2_sql_injection.py index 3312a23b9..8bf88cf6e 100644 --- a/bandit/plugins/psycopg2_sql_injection.py +++ b/bandit/plugins/psycopg2_sql_injection.py @@ -21,7 +21,7 @@ def psycopg2_sql_injection(context): - https://www.psycopg.org/docs/sql.html - .. versionadded:: 1.7.5 + .. versionadded:: 1.7.6 """ if context.is_module_imported_like("psycopg2.sql"): if context.call_function_name == "SQL":