bandit
bandit copied to clipboard
#nosec not working for multi-line strings in python 3.8
The Problem
Starting python3.8
adding #nosec
after a multi-line string has no effect. This was not the case in python 3.6 (and I think also 3.7)
How to Reproduce
Prepare two sample python source files
success.py
:
table = "my_table"
query = f"SELECT * FROM {table}" # nosec
fail.py
table = "my_table"
query = f"""
SELECT *
FROM {table}
""" # nosec
Set up python3.6
and python3.8
environments
$ python3.6 -m venv venv36
$ python3.8 -m venv venv38
Run bandit using python3.6
$ source ./venv36/bin/activate
$ pip install bandit==1.6.3
Run bandit on success.py
-- no issues.
$ bandit success.py
[main] INFO profile include tests: None
[main] INFO profile exclude tests: None
[main] INFO cli include tests: None
[main] INFO cli exclude tests: None
[main] INFO running on Python 3.6.12
[node_visitor] INFO Unable to find qualified name for module: success.py
Run started:2020-12-07 14:35:50.699373
Test results:
No issues identified.
Code scanned:
Total lines of code: 2
Total lines skipped (#nosec): 1
Run metrics:
Total issues (by severity):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Total issues (by confidence):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Files skipped (0):
Run bandit on fail.py
-- no issues either.
$ bandit fail.py
[main] INFO profile include tests: None
[main] INFO profile exclude tests: None
[main] INFO cli include tests: None
[main] INFO cli exclude tests: None
[main] INFO running on Python 3.6.12
[node_visitor] INFO Unable to find qualified name for module: fail.py
Run started:2020-12-07 14:25:36.277457
Test results:
No issues identified.
Code scanned:
Total lines of code: 5
Total lines skipped (#nosec): 1
Run metrics:
Total issues (by severity):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Total issues (by confidence):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Files skipped (0):
$ deactivate
Run bandit in python3.8
$ source ./venv38/bin/activate
$ pip install bandit==1.6.3
Run bandit on success.py
-- no issues.
$ bandit success.py
[main] INFO profile include tests: None
[main] INFO profile exclude tests: None
[main] INFO cli include tests: None
[main] INFO cli exclude tests: None
[main] INFO running on Python 3.8.6
[node_visitor] INFO Unable to find qualified name for module: success.py
Run started:2020-12-07 14:37:02.909155
Test results:
No issues identified.
Code scanned:
Total lines of code: 2
Total lines skipped (#nosec): 1
Run metrics:
Total issues (by severity):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Total issues (by confidence):
Undefined: 0.0
Low: 0.0
Medium: 0.0
High: 0.0
Files skipped (0):
Run bandit on fail.py
-- one issue is reported.
$ bandit fail.py
[main] INFO profile include tests: None
[main] INFO profile exclude tests: None
[main] INFO cli include tests: None
[main] INFO cli exclude tests: None
[main] INFO running on Python 3.8.6
[node_visitor] INFO Unable to find qualified name for module: fail.py
Run started:2020-12-07 14:26:41.664117
Test results:
>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction.
Severity: Medium Confidence: Low
Location: fail.py:2
More Info: https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html
1 table = "my_table"
2 query = f"""
3 SELECT *
4 FROM {table}
5 """ # nosec
--------------------------------------------------
Code scanned:
Total lines of code: 5
Total lines skipped (#nosec): 0
Run metrics:
Total issues (by severity):
Undefined: 0.0
Low: 0.0
Medium: 1.0
High: 0.0
Total issues (by confidence):
Undefined: 0.0
Low: 1.0
Medium: 0.0
High: 0.0
Files skipped (0):
$ deactivate
Expected Behaviour
The #nosec
clause should work both in python3.6
and python3.8
. In this concrete example bandit fail.py
should not fail in python3.8
.
Bandit Version
On python3.6
:
$ bandit --version
bandit 1.6.3
python version = 3.6.12 (default, Nov 6 2020, 13:08:49) [GCC Apple LLVM 12.0.0 (clang-1200.0.32.21)]
On python3.8
$ bandit --version
bandit 1.6.3
python version = 3.8.6 (default, Nov 6 2020, 13:26:24) [Clang 12.0.0 (clang-1200.0.32.21)]
Confirming it's also a problem on 3.9.7 on Windows
C:\test> bandit --version
bandit 1.7.0
python version = 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64 bit (AMD64)]
Confirmed with 3.8 & 3.9 on Linux.
It looks like the line number of the error is being reported as the first line of the multi line string (where we cannot put a nosec comment) whereas before it was the last line.
Using the report above as an example:
Test results:
>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction.
Severity: Medium Confidence: Low
Location: fail.py:2
More Info: https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html
1 table = "my_table"
2 query = f"""
3 SELECT *
4 FROM {table}
5 """ # nosec
The error is reported on line 2:
Location: fail.py:2
My workaround:
"""# nosec"""; query = f"""
SELECT *
FROM {table}
"""
My workaround:
"""# nosec"""; query = f""" SELECT * FROM {table} """
very nice. you also don't need that comma.
"""# nosec"""
query = f"""
select...
""""
works too.
A black compatible workaround
# fmt: off
query = ( # nosec
f"""
SELECT something,
WHERE foobar = {bar}
"""
)
# fmt: on
Still please fix. Especially using black this can be a pain in the ass ;-)
I also just experienced this in my pipeline. Checked with python:
- 3.7.12 working
- 3.8.10 not working
- 3.9.10 not working
I'm not able to get any of the mentioned workarounds to work. Only thing that worked for me for now was downgrading back to bandit 1.6.2.
I think this can be closed now. It is fixed by the linked pull request.
I have this problem with bandit 1.7.5 and Python 3.10.9. I'm using this version of the workaround.
connection,
sql=( # nosec
f"""
Can you share the whole piece of code (or minimal example) for which the bandit does not behave as expected?
@nevdelap after switching to the latest bandit version I had to move SQL nosec comments to the end of multiline strings before:
sql(
f""" # nosec
some SQL query
""",
)
after:
sql(
f"""
some SQL query
""", # nosec
)
Thanks @GeyseR. That works. All good.
A black compatible workaround
# fmt: off query = ( # nosec f""" SELECT something, WHERE foobar = {bar} """ ) # fmt: on
Thank you so much @CarliJoy!