Home Technical Support Running SAST and SCA Locally: Bandit and Safety Scanner Troubleshooting

Running SAST and SCA Locally: Bandit and Safety Scanner Troubleshooting

Last updated on Sep 08, 2026

Running SAST and SCA Locally: Bandit and Safety Scanner Troubleshooting

The Static Analysis Using Bandit and Software Component Analysis Using Safety exercises teach hands-on use of Python security scanners. These exercises appear across 4 courses. This article covers installation issues, scan failures, and interpreting results.


Table of Contents

  1. Bandit Installation
  2. Bandit Scan: Recursive and Output Formats
  3. Bandit Severity Filtering
  4. Bandit Exit Codes
  5. Safety Installation Errors
  6. Safety Policy File Required
  7. Safety Scan Output
  8. Common Questions

Bandit Installation

Install Bandit

pip3 install bandit==1.8.5

This installs bandit with dependencies: PyYAML, stevedore, rich, markdown-it-py, pygments, mdurl.

Verify Installation

bandit --help

If bandit: command not found, check your PATH or try python3 -m bandit --help.


Bandit Scan: Recursive and Output Formats

Recursive Scan

bandit -r . -f json | tee bandit-output.json

Flags:

Flag Purpose
-r . Recursively scan the current directory
-f json JSON output format
-o file.json Write output to file (alternative to tee)

Key concept: Always use -r for recursive scanning. Without it, bandit only scans files explicitly listed.

Output Formats

Bandit supports multiple output formats:

  • screen (default): Colored terminal output
  • json: Machine-readable, good for CI/CD pipelines
  • html: Browser-viewable report
  • csv: Spreadsheet format
  • xml: For tool integration
  • yaml: YAML format

Bandit Severity Filtering

Filter by Severity Level

Bandit findings have three severity levels. By default, all findings are shown:

bandit -r . -l     # LOW and above (default)
bandit -r . -ll    # MEDIUM and above
bandit -r . -lll   # HIGH only

Common scenario: In CI/CD pipelines, you often want to fail only on HIGH severity findings:

bandit -r . -lll   # Only fails if HIGH severity issues found

Understanding Results

A typical scan might find:

  • 1 HIGH severity issue
  • 1 MEDIUM severity issue
  • 5 LOW severity issues

Results are variable and depend on the codebase being scanned.


Bandit Exit Codes

Exit Code Meaning
0 No security issues found at the specified severity level
1 Security issues detected
2 Error during scan (invalid arguments, code parsing errors)

Key concept: Exit code 1 means vulnerabilities were found. This is expected in most real-world codebases and is not a scanner error.


Safety Installation Errors <a name="safety-install>

Install Safety

pip3 install safety==2.3.5

Build Dependencies May Be Missing

If pip fails to install Safety due to missing C build tools:

Error: Could not build wheels for safety

Fix: Install build dependencies first:

apt-get update && apt-get install -y build-essential python3-dev
pip3 install safety==2.3.5

Safety Policy File Required

.safety-policy.yml Must Exist Before Scanning

Without a policy file, Safety may fail:

No such file or directory: .safety-policy.yml

Fix: Create the policy file before running the scan:

cat > .safety-policy.yml <<EOF
security:
  ignore-vulnerabilities: {}
EOF

An empty ignore-vulnerabilities: {} means all vulnerabilities are reported. You can add specific vulnerability IDs to suppress them:

security:
  ignore-vulnerabilities:
    12345: {}  # Ignore vulnerability ID 12345

Safety Scan Output

Running the Scan

safety check -r requirements.txt --json | tee safety-output.json

Interpreting Results

A typical scan output shows vulnerable packages with CVE details:

Found 26 known vulnerability alerts affecting 15 packages

For example, Django 3.0 may have CVE-2022-34265 (SQL injection via Trunc/Extract).

Safety Exit Codes

Exit Code Meaning
0 No vulnerabilities found
64 Vulnerabilities found

Key concept: Exit code 64 is normal — it means the scanner did its job and found vulnerable dependencies.

Output Formats

safety check -r requirements.txt -o screen   # Terminal output
safety check -r requirements.txt -o json     # JSON output
safety check -r requirements.txt -o text     # Plain text
safety check -r requirements.txt -o bare     # Minimal output (just vuln IDs)

Common Questions

Question Answer
Bandit returns exit code 1 — is that an error? No. Exit code 1 means vulnerabilities were found. This is expected behavior.
How do I only see HIGH severity findings? Use bandit -r . -lll (three L's for HIGH only).
Safety fails with "No such file or directory: .safety-policy.yml." Create the policy file first: cat > .safety-policy.yml <<EOF ... EOF.
pip3 install safety fails with build errors. Install build dependencies: apt-get install -y build-essential python3-dev, then retry.
Where does Safety get its vulnerability database? Safety queries pyup.io's database online. An API key (--key) unlocks the full database.
How do I ignore a specific vulnerability in Safety? Add its ID to .safety-policy.yml under ignore-vulnerabilities.

Wrap-Up

Bandit (SAST) and Safety (SCA/OAST) are foundational Python security tools. Key takeaways:

  • Bandit scans source code for security issues. Use -r for recursive, -lll for HIGH-only, and -f json for machine-readable output.
  • Safety scans dependencies for known vulnerabilities. Requires .safety-policy.yml before scanning.
  • Both tools return non-zero exit codes when they find issues — this is expected, not an error.
  • Exit code 1 (Bandit) and exit code 64 (Safety) mean vulnerabilities were found.
  • Install build dependencies (build-essential python3-dev) if Safety pip install fails.

The DevSecOps Box is stateless — all installed packages and files are lost on page refresh.