# pycqa/bandit architecture

> Architecture diagram of the GitHub repository pycqa/bandit, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-05-13). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/pycqa/bandit
- Repository: https://github.com/pycqa/bandit

## Overview

1. Bandit is a Python security linter packaged as a library plus CLI. Its core runtime is the `bandit` package, and the primary execution path starts from `bandit/__main__.py` or `bandit/cli/main.py` when invoked as a command-line tool.

2. The main scan pipeline is: load configuration, discover test plugins, walk Python source files, build an AST, run security checks against AST nodes, collect issues, then format/report results. This is the central data flow that an architecture diagram should show.

3. `bandit/core` is the engine layer. It contains the AST traversal and orchestration pieces (`manager`, `node_visitor`, `tester`, `context`, `issue`, `metrics`, `config`, `extension_loader`). This layer owns file scanning, plugin invocation, issue aggregation, and run metadata.

4. The AST-based analysis boundary is important: Bandit reads Python source, parses it into AST, and evaluates nodes rather than executing code. `meta_ast.py` and `node_visitor.py` support this traversal, while `context.py` carries node-specific information into tests.

5. Security rules live mostly in `bandit/plugins`. These are the pluggable detectors for patterns like shell injection, SQL injection, hardcoded secrets, unsafe deserialization, insecure SSL/TLS, template/XSS issues, and unsafe model downloads. Each plugin is a focused rule module that emits findings when it matches an AST pattern.

6. `bandit/blacklists` provides a second rule mechanism for banned calls and imports. These are more table-driven checks, complementing the plugin system with explicit forbidden APIs and modules.

7. `bandit/cli` is the user-facing command layer. It handles argument parsing, baseline comparison, and config generation. The baseline feature is an architectural boundary for suppressing previously accepted findings so that only new issues are reported.

8. Reporting is separated into `bandit/formatters`. The same issue set can be rendered as screen text, plain text, JSON, YAML, CSV, XML, HTML, or SARIF. This formatter layer is the output boundary and is important for integrations with CI, code scanning tools, and human review.

9. The repository includes a large `examples/` corpus and `tests/` suite that validate detection behavior. The examples act as fixture-like inputs for many vulnerability patterns, while unit and functional tests cover CLI behavior, engine logic, and formatter output.

10. Packaging and distribution are handled through standard Python tooling: `setup.py`, `setup.cfg`, `requirements.txt`, and tox/pre-commit configs. The repo is released to PyPI and also built into a container image via GitHub Actions, which makes Bandit usable both as an installed CLI and as a Dockerized scanner.

11. Documentation is a first-class subsystem under `doc/`, built with Sphinx and published to Read the Docs. The docs mirror the internal architecture: configuration, blacklists, plugins, formatters, and CI/CD usage.

12. For an architecture diagram, the key boundaries are: source files in, AST analysis in the middle, plugins/blacklists as rule providers, formatter outputs on the other side, and CLI/config/baseline as orchestration around the engine. The external surfaces are Python source repositories, CI pipelines, PyPI, Read the Docs, and the published container image.

Main entry points: [`bandit/core/manager.py`](https://github.com/pycqa/bandit/blob/main/bandit/core/manager.py) (Manager), [`bandit/cli/main.py`](https://github.com/pycqa/bandit/blob/main/bandit/cli/main.py) (CLI), [`bandit/core/tester.py`](https://github.com/pycqa/bandit/blob/main/bandit/core/tester.py) (Tester), [`bandit/plugins/__init__.py`](https://github.com/pycqa/bandit/blob/main/bandit/plugins/__init__.py) (Plugins)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime["Runtime"]
  node_bandit_main["Entrypoints<br/>package entry<br/>[__main__.py]"]
  node_cli_main["CLI<br/>command layer<br/>[main.py]"]
  node_cli_baseline["Baseline<br/>suppression<br/>[baseline.py]"]
  node_cli_config["Config gen"]
end

subgraph group_engine["Engine"]
  node_manager["Manager<br/>scan coordinator<br/>[manager.py]"]
  node_config["Config<br/>runtime settings<br/>[config.py]"]
  node_extension_loader["Loader<br/>plugin discovery"]
  node_meta_ast(("AST parse<br/>parser<br/>[meta_ast.py]"))
  node_node_visitor["Visitor<br/>AST walker<br/>[node_visitor.py]"]
  node_tester["Tester<br/>rule runner<br/>[tester.py]"]
  node_context["Context<br/>analysis state<br/>[context.py]"]
  node_issue["Issue<br/>finding model<br/>[issue.py]"]
  node_metrics["Metrics<br/>run stats<br/>[metrics.py]"]
end

subgraph group_rules["Rules"]
  node_plugins["Plugins<br/>rule modules<br/>[__init__.py]"]
  node_blacklists["Blacklists<br/>banned APIs<br/>[__init__.py]"]
end

subgraph group_output["Reporting"]
  node_formatters["Formatters<br/>output adapters<br/>[__init__.py]"]
end

subgraph group_support["Support"]
  node_examples["Examples<br/>fixtures<br/>[__init__.py]"]
  node_tests["Tests<br/>verification<br/>[__init__.py]"]
  node_docs["Docs<br/>documentation<br/>[index.rst]"]
  node_packaging["Packaging<br/>release tooling<br/>[setup.py]"]
  node_docker_image[("Container image<br/>runtime artifact")]
end

node_bandit_main -->|"invokes"| node_cli_main
node_cli_main -->|"loads"| node_config
node_cli_main -->|"applies"| node_cli_baseline
node_cli_main -->|"generates"| node_cli_config
node_cli_main -->|"starts scan"| node_manager
node_manager -->|"discovers"| node_extension_loader
node_manager -->|"parses"| node_meta_ast
node_manager -->|"walks"| node_node_visitor
node_node_visitor -->|"dispatches"| node_tester
node_tester -->|"builds"| node_context
node_tester -->|"runs"| node_plugins
node_tester -->|"checks"| node_blacklists
node_plugins -->|"emits"| node_issue
node_blacklists -->|"emits"| node_issue
node_manager -->|"records"| node_metrics
node_manager -->|"collects"| node_issue
node_issue -->|"renders"| node_formatters
node_formatters -.->|"verified by"| node_tests
node_manager -.->|"verified by"| node_tests
node_plugins -.->|"exercised by"| node_examples
node_blacklists -.->|"documented in"| node_docs
node_plugins -.->|"documented in"| node_docs
node_formatters -.->|"documented in"| node_docs
node_packaging -->|"builds"| node_docker_image
node_packaging -.->|"publishes"| node_docs
node_packaging -.->|"guards"| node_tests

click node_bandit_main "https://github.com/pycqa/bandit/blob/main/bandit/__main__.py"
click node_cli_main "https://github.com/pycqa/bandit/blob/main/bandit/cli/main.py"
click node_cli_baseline "https://github.com/pycqa/bandit/blob/main/bandit/cli/baseline.py"
click node_cli_config "https://github.com/pycqa/bandit/blob/main/bandit/cli/config_generator.py"
click node_manager "https://github.com/pycqa/bandit/blob/main/bandit/core/manager.py"
click node_config "https://github.com/pycqa/bandit/blob/main/bandit/core/config.py"
click node_extension_loader "https://github.com/pycqa/bandit/blob/main/bandit/core/extension_loader.py"
click node_meta_ast "https://github.com/pycqa/bandit/blob/main/bandit/core/meta_ast.py"
click node_node_visitor "https://github.com/pycqa/bandit/blob/main/bandit/core/node_visitor.py"
click node_tester "https://github.com/pycqa/bandit/blob/main/bandit/core/tester.py"
click node_context "https://github.com/pycqa/bandit/blob/main/bandit/core/context.py"
click node_issue "https://github.com/pycqa/bandit/blob/main/bandit/core/issue.py"
click node_metrics "https://github.com/pycqa/bandit/blob/main/bandit/core/metrics.py"
click node_plugins "https://github.com/pycqa/bandit/blob/main/bandit/plugins/__init__.py"
click node_blacklists "https://github.com/pycqa/bandit/blob/main/bandit/blacklists/__init__.py"
click node_formatters "https://github.com/pycqa/bandit/blob/main/bandit/formatters/__init__.py"
click node_examples "https://github.com/pycqa/bandit/blob/main/examples/__init__.py"
click node_tests "https://github.com/pycqa/bandit/blob/main/tests/__init__.py"
click node_docs "https://github.com/pycqa/bandit/blob/main/doc/source/index.rst"
click node_packaging "https://github.com/pycqa/bandit/blob/main/setup.py"
click node_docker_image "https://github.com/pycqa/bandit/tree/main/docker/Dockerfile"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_bandit_main,node_cli_main,node_cli_baseline,node_cli_config toneBlue
class node_manager,node_config,node_extension_loader,node_meta_ast,node_node_visitor,node_tester,node_context,node_issue,node_metrics toneAmber
class node_plugins,node_blacklists toneMint
class node_formatters toneRose
class node_examples,node_tests,node_docs,node_packaging,node_docker_image toneIndigo
```

## Components

### Runtime

Python package and CLI entrypoints

- [Entrypoints](https://github.com/pycqa/bandit/blob/main/bandit/__main__.py): package entry · CLI and module entrypoints into Bandit · `bandit/__main__.py`
- [CLI](https://github.com/pycqa/bandit/blob/main/bandit/cli/main.py): command layer · Argument parsing, baseline handling, and config generation · `bandit/cli/main.py`
- [Baseline](https://github.com/pycqa/bandit/blob/main/bandit/cli/baseline.py): suppression · Compares against saved findings to suppress accepted issues · `bandit/cli/baseline.py`
- [Config gen](https://github.com/pycqa/bandit/blob/main/bandit/cli/config_generator.py): utility · Generates starter configuration for scans · `bandit/cli/config_generator.py`

### Engine

Core AST scan orchestration and analysis

- [Manager](https://github.com/pycqa/bandit/blob/main/bandit/core/manager.py): scan coordinator · Coordinates file discovery, scanning, and result collection · `bandit/core/manager.py`
- [Config](https://github.com/pycqa/bandit/blob/main/bandit/core/config.py): runtime settings · Loads and normalizes scan configuration · `bandit/core/config.py`
- [Loader](https://github.com/pycqa/bandit/blob/main/bandit/core/extension_loader.py): plugin discovery · Discovers and loads test plugins · `bandit/core/extension_loader.py`
- [AST parse](https://github.com/pycqa/bandit/blob/main/bandit/core/meta_ast.py): parser · Parses Python source into AST form for analysis · `bandit/core/meta_ast.py`
- [Visitor](https://github.com/pycqa/bandit/blob/main/bandit/core/node_visitor.py): AST walker · Walks AST nodes and dispatches checks · `bandit/core/node_visitor.py`
- [Tester](https://github.com/pycqa/bandit/blob/main/bandit/core/tester.py): rule runner · Executes registered checks against nodes · `bandit/core/tester.py`
- [Context](https://github.com/pycqa/bandit/blob/main/bandit/core/context.py): analysis state · Carries node-specific data into checks · `bandit/core/context.py`
- [Issue](https://github.com/pycqa/bandit/blob/main/bandit/core/issue.py): finding model · Represents a security finding and its metadata · `bandit/core/issue.py`
- [Metrics](https://github.com/pycqa/bandit/blob/main/bandit/core/metrics.py): run stats · Collects scan counts and run metadata · `bandit/core/metrics.py`

### Rules

Pluggable security detectors and blacklist checks

- [Plugins](https://github.com/pycqa/bandit/blob/main/bandit/plugins/__init__.py): rule modules · Focused AST detectors for security patterns · `bandit/plugins/__init__.py`
- [Blacklists](https://github.com/pycqa/bandit/blob/main/bandit/blacklists/__init__.py): banned APIs · Table-driven checks for forbidden imports and calls · `bandit/blacklists/__init__.py`

### Reporting

Formatter and output layers

- [Formatters](https://github.com/pycqa/bandit/blob/main/bandit/formatters/__init__.py): output adapters · Render findings for humans and tool integrations · `bandit/formatters/__init__.py`

### Support

Docs, examples, tests, and packaging

- [Examples](https://github.com/pycqa/bandit/blob/main/examples/__init__.py): fixtures · Representative vulnerable and safe code samples · `examples/__init__.py`
- [Tests](https://github.com/pycqa/bandit/blob/main/tests/__init__.py): verification · Unit and functional coverage for CLI, engine, and formatters · `tests/__init__.py`
- [Docs](https://github.com/pycqa/bandit/blob/main/doc/source/index.rst): documentation · Sphinx docs for usage, rules, and integrations · `doc/source/index.rst`
- [Packaging](https://github.com/pycqa/bandit/blob/main/setup.py): release tooling · Build, publish, and repository tooling for distribution · `setup.py`
- [Container image](https://github.com/pycqa/bandit/tree/main/docker/Dockerfile): runtime artifact · Published Docker image for scanner execution · `docker/Dockerfile`

## Connections

- Entrypoints → CLI: invokes · Module and console entrypoints hand off to the CLI
- CLI → Config: loads · CLI loads runtime configuration for a scan
- CLI → Baseline: applies · Baseline comparison suppresses previously accepted issues
- CLI → Config gen: generates · CLI can emit a starter configuration file
- CLI → Manager: starts scan · CLI delegates scan execution to the engine
- Manager → Loader: discovers · Manager loads available plugin rules
- Manager → AST parse: parses · Source files are converted into ASTs
- Manager → Visitor: walks · Manager drives AST traversal over files
- Visitor → Tester: dispatches · Visitor sends each node to registered tests
- Tester → Context: builds · Tests receive node-local context objects
- Tester → Plugins: runs · Plugin detectors evaluate AST patterns
- Tester → Blacklists: checks · Blacklist rules flag forbidden calls and imports
- Plugins → Issue: emits · Matching rules create findings
- Blacklists → Issue: emits · Forbidden API matches become findings
- Manager → Metrics: records · Scan progress and run metadata are tracked
- Manager → Issue: collects · Manager aggregates findings from all checks
- Issue → Formatters: renders · Findings are formatted for each output target
- Formatters → Tests: verified by · Formatter behavior is covered by unit tests
- Manager → Tests: verified by · Engine behavior is covered by functional and unit tests
- Plugins → Examples: exercised by · Example corpus supplies representative detector inputs
- Blacklists → Docs: documented in · Blacklist rules are described in the docs
- Plugins → Docs: documented in · Plugin rules are documented in Sphinx pages
- Formatters → Docs: documented in · Output formats are documented for users and integrations
- Packaging → Container image: builds · Release tooling produces a container image
- Packaging → Docs: publishes · Docs are built and published through project tooling
- Packaging → Tests: guards · CI and test tooling validate packaging and release paths
