4
A security linter from OpenStack Security
9
Bandit is a tool designed to find common security issues in Python code. To do
10
this Bandit processes each file, builds an AST from it, and runs appropriate
11
plugins against the AST nodes. Once Bandit has finished scanning all the files
12
it generates a report.
16
Bandit is distributed on PyPI. The best way to install it is with pip:
19
***Create a virtual environment (optional):***
26
# Or, if you're working with a Python 3 project
31
bandit -r path/to/your/code
34
Bandit can also be installed from source. To do so, download the source
35
tarball from PyPI, then install it:
37
python setup.py install
42
Example usage across a code tree:
44
bandit -r ~/openstack-repo/keystone
46
Example usage across the examples/ directory, showing three lines of context
47
and only reporting on the high-severity issues:
49
bandit examples/*.py -n 3 -lll
51
Bandit can be run with profiles. To run Bandit against the examples directory
52
using only the plugins listed in the ShellInjection profile:
54
bandit examples/*.py -p ShellInjection
59
usage: bandit [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE]
60
[-p PROFILE] [-l] [-f {txt,json,csv,xml}] [-o OUTPUT_FILE] [-v]
64
Bandit - a Python source code analyzer.
67
targets source file(s) or directory(s) to be tested
70
-h, --help show this help message and exit
71
-r, --recursive process files in subdirectories
72
-a {file,vuln}, --aggregate {file,vuln}
73
group results by vulnerability type or file it occurs
75
-n CONTEXT_LINES, --number CONTEXT_LINES
76
max number of code lines to display for each issue
78
-c CONFIG_FILE, --configfile CONFIG_FILE
79
test config file, defaults to /etc/bandit/bandit.yaml,
80
or./bandit.yaml if not given
81
-p PROFILE, --profile PROFILE
82
test set profile in config to use (defaults to all
84
-l, --level results level filter
85
-f {csv,json,txt,xml}, --format {csv,json,txt,xml}
87
-o OUTPUT_FILE, --output OUTPUT_FILE
88
write report to filename
89
-v, --verbose show extra information like excluded and included
91
-d, --debug turn on debug mode
96
The Bandit config file is used to set several things, including:
97
- profiles - defines group of tests which should or shouldn't be run
98
- exclude_dirs - sections of the path, that if matched, will be excluded from
100
- plugin configs - used to tune plugins, for example: by tuning
101
blacklist_imports, you can set which imports should be flagged
102
- other - plugins directory, included file types, shell display
105
Bandit requires a config file. Bandit will use bandit.yaml in the following
108
- Bandit config file specified with -c command line option
109
- bandit.yaml file from current working directory
110
- bandit.yaml file from ~/.config/bandit/
111
- bandit.yaml file in config/ directory of the Bandit package
116
In the event that a line of code triggers a Bandit issue, but that the line
117
has been reviewed and the issue is a false positive or acceptable for some
118
other reason, the line can be marked with a '# nosec' and any results
119
associated with it will not be reported.
121
For example, although this line may cause Bandit to report a potential
122
security issue, it will not be reported::
124
self.process = subprocess.Popen('/bin/echo', shell=True) # nosec
129
Vulnerability tests or 'plugins' are defined in files in the plugins directory.
131
Tests are written in Python and are autodiscovered from the plugins directory.
132
Each test can examine one or more type of Python statements. Tests are marked
133
with the types of Python statements they examine (for example: function call,
134
string, import, etc).
136
Tests are executed by the BanditNodeVisitor object as it visits each node in
139
Test results are maintained in the BanditResultStore and aggregated for output
140
at the completion of a test run.
146
- Identify a vulnerability to build a test for, and create a new file in
147
examples/ that contains one or more cases of that vulnerability.
148
- Consider the vulnerability you're testing for, mark the function with one
149
or more of the appropriate decorators:
151
- @checks('Import', 'ImportFrom')
153
- Create a new Python source file to contain your test, you can reference
154
existing tests for examples.
155
- The function that you create should take a parameter "context" which is
156
an instance of the context class you can query for information about the
157
current element being examined. You can also get the raw AST node for
158
more advanced use cases. Please see the context.py file for more.
159
- Extend your Bandit configuration file as needed to support your new test.
160
- Execute Bandit against the test file you defined in examples/ and ensure
161
that it detects the vulnerability. Consider variations on how this
162
vulnerability might present itself and extend the example file and the test
163
function accordingly.
168
Bandit allows users to write and register extensions for checks and formatters.
169
Bandit will load plugins from two entry-points:
171
- `bandit.formatters`
174
Formatters need to accept 4 things:
176
- `result_store`: An instance of `bandit.core.BanditResultStore`
177
- `file_list`: The list of files which were inspected in the scope
178
- `scores`: The scores awarded to each file in the scope
179
- `excluded_files`: The list of files that were excluded from the scope
181
Plugins tend to take advantage of the `bandit.checks` decorator which allows
182
the author to register a check for a particular type of AST node. For example,
184
@bandit.checks('Call')
185
def prohibit_unsafe_deserialization(context):
186
if 'unsafe_load' in context.call_function_name_qual:
188
severity=bandit.HIGH,
189
confidence=bandit.HIGH,
190
text="Unsafe deserialization detected."
193
To register your plugin, you have two options:
195
1. If you're using setuptools directly, add something like the following to
198
# If you have an imaginary bson formatter in the bandit_bson module
199
# and a function called `formatter`.
200
entry_points={'bandit.formatters': ['bson = bandit_bson:formatter']}
201
# Or a check for using mako templates in bandit_mako that
202
entry_points={'bandit.plugins': ['mako = bandit_mako']}
204
2. If you're using pbr, add something like the following to your `setup.cfg`
209
bson = bandit_bson:formatter
215
Contributions to Bandit are always welcome! We can be found on #openstack-security
218
The best way to get started with Bandit is to grab the source:
220
git clone https://git.openstack.org/stackforge/bandit.git
222
You can test any changes with tox:
231
Under Which Version of Python Should I Install Bandit?
232
------------------------------------------------------
233
The answer to this question depends on the project(s) you will be running
234
Bandit against. If your project is only compatible with Python 2.7, you
235
should install Bandit to run under Python 2.7. If your project is only
236
compatible with Python 3.4, then use 3.4. If your project supports both, you
237
*could* run Bandit with both versions but you don't have to.
239
Bandit uses the `ast` module from Python's standard library in order to
240
analyze your Python code. The `ast` module is only able to parse Python code
241
that is valid in the version of the interpreter from which it is imported. In
242
other words, if you try to use Python 2.7's `ast` module to parse code written
243
for 3.4 that uses, for example, `yield from` with asyncio, then you'll have
244
syntax errors that will prevent Bandit from working properly. Alternatively,
245
if you are relying on 2.7's octal notation of `0777` then you'll have a syntax
246
error if you run Bandit on 3.4.
252
Bandit wiki: https://wiki.openstack.org/wiki/Security/Projects/Bandit
254
Python AST module documentation: https://docs.python.org/2/library/ast.html
256
Green Tree Snakes - the missing Python AST docs:
257
http://greentreesnakes.readthedocs.org/en/latest/
259
Documentation of the various types of AST nodes that Bandit currently covers
260
or could be extended to cover:
261
http://greentreesnakes.readthedocs.org/en/latest/nodes.html