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

Detect misuse of psycopg2.sql.SQL composable #608

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
37 changes: 37 additions & 0 deletions bandit/plugins/psycopg2_sql_injection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-License-Identifier: Apache-2.0
import ast

import bandit
from bandit.core import test_properties as test
ericwb marked this conversation as resolved.
Show resolved Hide resolved


@test.checks("Call")
@test.test_id("B613")
def psycopg2_sql_injection(context):
"""**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
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.7.5
ericwb marked this conversation as resolved.
Show resolved Hide resolved
"""
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=(
ericwb marked this conversation as resolved.
Show resolved Hide resolved
"Possible SQL injection vector through instantiation "
"of psycopg2.sql.SQL composable object on an argument "
"other than a string literal."
),
)
4 changes: 4 additions & 0 deletions examples/psycopg2_sql_injection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from psycopg2 import sql

table = 'users; drop table users; --'
sql.SQL('select * from {}').format(sql.SQL(table))
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ bandit.plugins =
#bandit/plugins/tarfile_unsafe_members.py
tarfile_unsafe_members = bandit.plugins.tarfile_unsafe_members:tarfile_unsafe_members

# 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
Expand Down
8 changes: 8 additions & 0 deletions tests/functional/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,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 = {
Expand Down