AppSecNews
SAST Open source Established Verified profile

Bandit

by PyCQA

An AST-based security linter for Python that flags common insecure patterns such as unsafe deserialization, shell injection and weak crypto.

No endorsements yet

Run Bandit in production? A named recommendation helps the next team shortlisting it.

Recommend this tool

Endorsers verify their identity through LinkedIn. Titles and companies are self declared, shown as they were when each person signed, and reviewed by an editor before anything is published. Endorsements are never paid for.

What it does

Bandit parses each Python file into an abstract syntax tree and walks the tree running a set of plugins against specific node types. A plugin might fire on a call to subprocess.Popen with shell=True, on yaml.load without a safe loader, on pickle.loads, on hashlib.md5, or on a hardcoded password assigned to a variable whose name looks like a credential. Each hit becomes an issue with a severity rating, a confidence rating, and a link to the relevant plugin documentation.

The important detail is that this is syntactic, not data flow. Bandit does not trace a value from an HTTP request parameter into a SQL string. It recognizes shapes: this function, called this way, is usually a problem. That design keeps it fast enough to run on every commit, at the cost of missing anything that depends on where a value came from. Findings can be suppressed inline with a # nosec comment, and the plugin set can be filtered by test ID or severity threshold.

Where it fits

Bandit belongs on the developer laptop and in the pull request. It is commonly wired in as a pre-commit hook or a CI job that fails the build above a severity and confidence floor. Developers usually own it rather than the security team, which is the right arrangement given the volume of low severity noise it produces. Nothing needs to be true beforehand except that the code parses under the Python version Bandit is running on.

Strengths

  • Runs in seconds on most repositories with no build step, no compilation, and no dependency resolution.
  • The plugin model is small enough that writing a custom check for an in-house dangerous helper is a realistic afternoon of work.
  • Severity and confidence are reported separately, which lets you gate on high severity plus high confidence and triage the rest asynchronously.

Limitations

  • No taint tracking. Injection flaws that depend on untrusted input reaching a sink are largely invisible unless the sink call itself looks wrong.
  • High false positive rate on patterns like assert usage, random for non-cryptographic purposes, and binding to all interfaces, all of which are fine in plenty of contexts.
  • Python only, and framework-unaware: it does not understand Django, Flask or FastAPI routing, so it cannot tell an internet-facing handler from a test fixture.

Who it suits

A good default for any Python team that wants a security baseline in CI without a procurement conversation. It is the wrong choice if you need interprocedural analysis or defensible audit evidence. Treat it as a linter with a security flavor and pair it with a taint-aware scanner when the application handles untrusted input.

Used Bandit? Recommend it under your own name and title.

Recommend this tool