Bandit — the security linter from PyCQA that reads Python source as a syntax tree and reports the constructs that tend to become vulnerabilities — is the tool that made static security analysis a routine part of Python development. Originally written inside the OpenStack Security Project and later rehomed to the Python Code Quality Authority (PyCQA), Bandit parses each file with Python’s own ast module, runs a library of plugins over the resulting nodes, and prints a report of what it found. It is free software under the Apache-2.0 licence, published on PyPI as bandit, and the current release is 1.9.4 (February 2026); the repository is under active development with more than 8,300 stars. Where a linter such as Ruff or flake8 polices style, Bandit polices behaviour: hardcoded passwords, disabled TLS verification, shell=True subprocesses, weak hashing, unsafe YAML deserialisation, SQL built by string concatenation and template engines with autoescaping switched off. It needs no account, no service and no build server — pip install bandit and a target directory are enough.
ast module the interpreter uses and runs plugins against the tree nodes. A call is judged by what it actually is — its fully-qualified name, its arguments, its context — so feedback is far more precise than a grep for suspicious strings, and it can only ever inspect code that is syntactically valid.assert_used, exec_used, set_bad_file_permissions, hardcoded_password_string, try_except_pass, request_without_timeout), B2xx application and framework misconfiguration (flask_debug_true, tarfile_unsafe_members), B3xx and B4xx blacklisted calls and imports (hashlib), B5xx cryptography (request_with_no_cert_validation, ssl_with_bad_version, weak_cryptographic_key, yaml_load, ssh_no_host_key_verification), B6xx injection (subprocess_popen_with_shell_equals_true, hardcoded_sql_expressions, django_rawsql_used, pytorch_load, huggingface_unsafe_download) and B7xx XSS (jinja2_autoescape_false, django_mark_safe, markupsafe_markup_xss).# nosec to silence everything on it, or scoped to specific tests and names — # nosec B602, B607 or # nosec assert_used. The narrow form is deliberate: it keeps suppressing what you reviewed while still catching a different vulnerability later added to the same line..bandit INI file in the project root (picked up automatically when Bandit runs with -r), or a YAML/TOML file passed with -c, can set targets, exclude/exclude_dirs, skips and tests, and override individual plugins. Bandit 1.0+ made the config file optional and understands [tool.bandit] in pyproject.toml.bandit-config-generator walks every discovered plugin and emits a template config block for each, so you can start from the real defaults and delete what you accept instead of guessing option names.text (also screen), json, csv, xml, yaml, html and sarif. The SARIF formatter is what lets Bandit findings appear inline on a GitHub pull-request diff via code scanning, like any other security tool.-b takes a previous report as a baseline so only new issues are reported; that is how a team adds Bandit to a large legacy repository without drowning in pre-existing findings.@checks('Call'), @checks('Import', 'ImportFrom') or @checks('Str') and register it through the bandit.plugins entry point: in-house rules ship as a normal Python package and plug straight into the same report.ghcr.io/pycqa/bandit/bandit for amd64 and arm64 (plus armv7/armv8), each signed with Sigstore cosign so the provenance of the image can be verified, and packaged for Ubuntu, Homebrew and FreeBSD.Most exploitable bugs are not sophisticated. They are a default password left in a config loader, a verify=False added to make a self-signed certificate work, an eval() on user input, a temporary file written to a predictable path, or a password hashed with a function never designed for it. Each of those has an idiomatic Python shape that Bandit recognises, and each is far cheaper to remove before the code ships than to find in an incident review. Because Bandit works on the syntax tree rather than on text, it reports the construct rather than the string: it knows the difference between a call to subprocess.Popen with a shell and a call to a function that merely happens to be named the same way in your own module. It is also entirely local — no source is sent anywhere, there is no dashboard to buy and no telemetry — which matters when the code being scanned is a client’s or a regulated workload. The practical reason it has lasted since the OpenStack years is the granularity of its output: severity and confidence are separate axes, suppression can be scoped to a single test, and a baseline turns a thousand legacy findings into a short list of new ones. That is what makes it adoptable on day one and tolerable on day one thousand.
bandit -r src/ as a quick security pass before opening a pull request.S rule set so new code is checked as it is written, not only in CI.hardcoded_bind_all_interfaces hit next to a development server started without a debug flag.S rule set. If your project already runs Ruff, enabling those rules gives Bandit-equivalent checks in the same pass; standalone Bandit remains the more complete implementation, with config generation, baselines, SARIF output and the plugin entry-point API. Not listed in the directory yet.Any platform with Python 3.10 or newer — Linux, macOS and Windows. Install from PyPI with pip install bandit (the bandit[toml] extra enables TOML configuration), from the official container image ghcr.io/pycqa/bandit/bandit, or from the distribution packages on Ubuntu, Homebrew and FreeBSD. It also runs as a pre-commit hook, a GitHub Action, a Jenkins plugin, or inside the editors that integrate it — VS Code, Sublime Text, Vim/Neovim and Emacs.
Apache-2.0 — the Bandit library and its plugins are provided under the terms of the Apache License 2.0. There is no open-core split, no paid tier and no service to subscribe to; the same code is the product.
documentation on Read the Docs · source on GitHub · package on PyPI · also see the Security & Privacy category for more tools that put guardrails around code and systems, or browse the full directory.