Full Code of PyCQA/bandit for AI

main b46fa3a27236 cached
291 files
778.0 KB
206.9k tokens
709 symbols
1 requests
Download .txt
Showing preview only (846K chars total). Download the full file or copy to clipboard to get everything.
Repository: PyCQA/bandit
Branch: main
Commit: b46fa3a27236
Files: 291
Total size: 778.0 KB

Directory structure:
gitextract_siphom_i/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── Feature_request.md
│   │   ├── bug-report.yml
│   │   └── config.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── build-publish-image.yml
│       ├── dependency-review.yml
│       ├── publish-to-pypi.yml
│       ├── publish-to-test-pypi.yml
│       └── pythonpackage.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .pre-commit-hooks.yaml
├── .readthedocs.yaml
├── .stestr.conf
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.rst
├── SECURITY.md
├── bandit/
│   ├── __init__.py
│   ├── __main__.py
│   ├── blacklists/
│   │   ├── __init__.py
│   │   ├── calls.py
│   │   ├── imports.py
│   │   └── utils.py
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── baseline.py
│   │   ├── config_generator.py
│   │   └── main.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── blacklisting.py
│   │   ├── config.py
│   │   ├── constants.py
│   │   ├── context.py
│   │   ├── docs_utils.py
│   │   ├── extension_loader.py
│   │   ├── issue.py
│   │   ├── manager.py
│   │   ├── meta_ast.py
│   │   ├── metrics.py
│   │   ├── node_visitor.py
│   │   ├── test_properties.py
│   │   ├── test_set.py
│   │   ├── tester.py
│   │   └── utils.py
│   ├── formatters/
│   │   ├── __init__.py
│   │   ├── csv.py
│   │   ├── custom.py
│   │   ├── html.py
│   │   ├── json.py
│   │   ├── sarif.py
│   │   ├── screen.py
│   │   ├── text.py
│   │   ├── utils.py
│   │   ├── xml.py
│   │   └── yaml.py
│   └── plugins/
│       ├── __init__.py
│       ├── app_debug.py
│       ├── asserts.py
│       ├── crypto_request_no_cert_validation.py
│       ├── django_sql_injection.py
│       ├── django_xss.py
│       ├── exec.py
│       ├── general_bad_file_permissions.py
│       ├── general_bind_all_interfaces.py
│       ├── general_hardcoded_password.py
│       ├── general_hardcoded_tmp.py
│       ├── hashlib_insecure_functions.py
│       ├── huggingface_unsafe_download.py
│       ├── injection_paramiko.py
│       ├── injection_shell.py
│       ├── injection_sql.py
│       ├── injection_wildcard.py
│       ├── insecure_ssl_tls.py
│       ├── jinja2_templates.py
│       ├── logging_config_insecure_listen.py
│       ├── mako_templates.py
│       ├── markupsafe_markup_xss.py
│       ├── pytorch_load.py
│       ├── request_without_timeout.py
│       ├── snmp_security_check.py
│       ├── ssh_no_host_key_verification.py
│       ├── tarfile_unsafe_members.py
│       ├── trojansource.py
│       ├── try_except_continue.py
│       ├── try_except_pass.py
│       ├── weak_cryptographic_key.py
│       └── yaml_load.py
├── doc/
│   ├── requirements.txt
│   └── source/
│       ├── blacklists/
│       │   ├── blacklist_calls.rst
│       │   ├── blacklist_imports.rst
│       │   └── index.rst
│       ├── ci-cd/
│       │   ├── github-actions.rst
│       │   └── index.rst
│       ├── conf.py
│       ├── config.rst
│       ├── faq.rst
│       ├── formatters/
│       │   ├── csv.rst
│       │   ├── custom.rst
│       │   ├── html.rst
│       │   ├── index.rst
│       │   ├── json.rst
│       │   ├── sarif.rst
│       │   ├── screen.rst
│       │   ├── text.rst
│       │   ├── xml.rst
│       │   └── yaml.rst
│       ├── index.rst
│       ├── integrations.rst
│       ├── man/
│       │   └── bandit.rst
│       ├── plugins/
│       │   ├── b101_assert_used.rst
│       │   ├── b102_exec_used.rst
│       │   ├── b103_set_bad_file_permissions.rst
│       │   ├── b104_hardcoded_bind_all_interfaces.rst
│       │   ├── b105_hardcoded_password_string.rst
│       │   ├── b106_hardcoded_password_funcarg.rst
│       │   ├── b107_hardcoded_password_default.rst
│       │   ├── b108_hardcoded_tmp_directory.rst
│       │   ├── b109_password_config_option_not_marked_secret.rst
│       │   ├── b110_try_except_pass.rst
│       │   ├── b111_execute_with_run_as_root_equals_true.rst
│       │   ├── b112_try_except_continue.rst
│       │   ├── b113_request_without_timeout.rst
│       │   ├── b201_flask_debug_true.rst
│       │   ├── b202_tarfile_unsafe_members.rst
│       │   ├── b324_hashlib.rst
│       │   ├── b501_request_with_no_cert_validation.rst
│       │   ├── b502_ssl_with_bad_version.rst
│       │   ├── b503_ssl_with_bad_defaults.rst
│       │   ├── b504_ssl_with_no_version.rst
│       │   ├── b505_weak_cryptographic_key.rst
│       │   ├── b506_yaml_load.rst
│       │   ├── b507_ssh_no_host_key_verification.rst
│       │   ├── b508_snmp_insecure_version.rst
│       │   ├── b509_snmp_weak_cryptography.rst
│       │   ├── b601_paramiko_calls.rst
│       │   ├── b602_subprocess_popen_with_shell_equals_true.rst
│       │   ├── b603_subprocess_without_shell_equals_true.rst
│       │   ├── b604_any_other_function_with_shell_equals_true.rst
│       │   ├── b605_start_process_with_a_shell.rst
│       │   ├── b606_start_process_with_no_shell.rst
│       │   ├── b607_start_process_with_partial_path.rst
│       │   ├── b608_hardcoded_sql_expressions.rst
│       │   ├── b609_linux_commands_wildcard_injection.rst
│       │   ├── b610_django_extra_used.rst
│       │   ├── b611_django_rawsql_used.rst
│       │   ├── b612_logging_config_insecure_listen.rst
│       │   ├── b613_trojansource.rst
│       │   ├── b614_pytorch_load.rst
│       │   ├── b615_huggingface_unsafe_download.rst
│       │   ├── b701_jinja2_autoescape_false.rst
│       │   ├── b702_use_of_mako_templates.rst
│       │   ├── b703_django_mark_safe.rst
│       │   ├── b704_markupsafe_markup_xss.rst
│       │   └── index.rst
│       └── start.rst
├── docker/
│   └── Dockerfile
├── examples/
│   ├── __init__.py
│   ├── assert.py
│   ├── binding.py
│   ├── cipher-modes.py
│   ├── ciphers.py
│   ├── crypto-md5.py
│   ├── dill.py
│   ├── django_sql_injection_extra.py
│   ├── django_sql_injection_raw.py
│   ├── eval.py
│   ├── exec.py
│   ├── flask_debug.py
│   ├── ftplib.py
│   ├── hardcoded-passwords.py
│   ├── hardcoded-tmp.py
│   ├── hashlib_new_insecure_functions.py
│   ├── httpoxy_cgihandler.py
│   ├── httpoxy_twisted_directory.py
│   ├── httpoxy_twisted_script.py
│   ├── huggingface_unsafe_download.py
│   ├── imports-aliases.py
│   ├── imports-from.py
│   ├── imports-function.py
│   ├── imports-with-importlib.py
│   ├── imports.py
│   ├── init-py-test/
│   │   ├── __init__.py
│   │   └── subdirectory-okay.py
│   ├── jinja2_templating.py
│   ├── jsonpickle.py
│   ├── logging_config_insecure_listen.py
│   ├── long_set.py
│   ├── mako_templating.py
│   ├── mark_safe.py
│   ├── mark_safe_insecure.py
│   ├── mark_safe_secure.py
│   ├── markupsafe_markup_xss.py
│   ├── markupsafe_markup_xss_allowed_calls.py
│   ├── markupsafe_markup_xss_extend_markup_names.py
│   ├── marshal_deserialize.py
│   ├── mktemp.py
│   ├── multiline_statement.py
│   ├── new_candidates-all.py
│   ├── new_candidates-none.py
│   ├── new_candidates-nosec.py
│   ├── new_candidates-some.py
│   ├── no_host_key_verification.py
│   ├── nonsense.py
│   ├── nonsense2.py
│   ├── nosec.py
│   ├── okay.py
│   ├── os-chmod.py
│   ├── os-exec.py
│   ├── os-popen.py
│   ├── os-spawn.py
│   ├── os-startfile.py
│   ├── os_system.py
│   ├── pandas_read_pickle.py
│   ├── paramiko_injection.py
│   ├── partial_path_process.py
│   ├── pickle_deserialize.py
│   ├── popen_wrappers.py
│   ├── pycrypto.py
│   ├── pycryptodome.py
│   ├── pyghmi.py
│   ├── pytorch_load.py
│   ├── random_module.py
│   ├── requests-missing-timeout.py
│   ├── requests-ssl-verify-disabled.py
│   ├── shelve_open.py
│   ├── skip.py
│   ├── snmp.py
│   ├── sql_multiline_statements.py
│   ├── sql_statements.py
│   ├── ssl-insecure-version.py
│   ├── subprocess_shell.py
│   ├── tarfile_extractall.py
│   ├── telnetlib.py
│   ├── trojansource.py
│   ├── trojansource_latin1.py
│   ├── try_except_continue.py
│   ├── try_except_pass.py
│   ├── unverified_context.py
│   ├── urlopen.py
│   ├── weak_cryptographic_key_sizes.py
│   ├── wildcard-injection.py
│   ├── xml_etree_celementtree.py
│   ├── xml_etree_elementtree.py
│   ├── xml_expatbuilder.py
│   ├── xml_expatreader.py
│   ├── xml_minidom.py
│   ├── xml_pulldom.py
│   ├── xml_sax.py
│   ├── xml_xmlrpc.py
│   └── yaml_load.py
├── funding.json
├── pylintrc
├── requirements.txt
├── scripts/
│   └── main.py
├── setup.cfg
├── setup.py
├── test-requirements.txt
├── tests/
│   ├── __init__.py
│   ├── functional/
│   │   ├── __init__.py
│   │   ├── test_baseline.py
│   │   ├── test_functional.py
│   │   └── test_runtime.py
│   └── unit/
│       ├── __init__.py
│       ├── cli/
│       │   ├── __init__.py
│       │   ├── test_baseline.py
│       │   ├── test_config_generator.py
│       │   └── test_main.py
│       ├── core/
│       │   ├── __init__.py
│       │   ├── test_blacklisting.py
│       │   ├── test_config.py
│       │   ├── test_context.py
│       │   ├── test_docs_util.py
│       │   ├── test_issue.py
│       │   ├── test_manager.py
│       │   ├── test_meta_ast.py
│       │   ├── test_test_set.py
│       │   └── test_util.py
│       └── formatters/
│           ├── __init__.py
│           ├── test_csv.py
│           ├── test_custom.py
│           ├── test_html.py
│           ├── test_json.py
│           ├── test_sarif.py
│           ├── test_screen.py
│           ├── test_text.py
│           ├── test_xml.py
│           └── test_yaml.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
*       @ericwb @lukehinds @sigmavirus24


================================================
FILE: .github/FUNDING.yml
================================================
custom: ["https://psfmember.org/civicrm/contribute/transact/?reset=1&id=42"]
github: [ericwb]
tidelift: pypi/bandit


================================================
FILE: .github/ISSUE_TEMPLATE/Feature_request.md
================================================
---
name: "\U0001F680 Feature request"
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.

Love this idea? Give it a 👍. We prioritize fulfilling features with the most 👍.


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: 🐛 Bug report
description: Create a report to help us improve
labels: bug

body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!

  - type: textarea
    id: describe-bug
    attributes:
      label: Describe the bug
      description: A clear and concise description of what the bug is.
    validations:
      required: true

  - type: textarea
    id: reproduction-steps
    attributes:
      label: Reproduction steps
      description: Steps to reproduce the behavior
      value: |
        1.
        2.
        3.
        ...
      render: bash
    validations:
      required: true

  - type: textarea
    id: expected-behavior
    attributes:
      label: Expected behavior
      description: A clear and concise description of what you expected to happen.
    validations:
      required: true

  - type: dropdown
    id: bandit-version
    attributes:
      label: Bandit version
      description: Run "bandit --version" if unsure of version number
      options:
        - 1.9.1 (Default)
        - 1.9.0
        - 1.8.6
        - 1.8.5
        - 1.8.4
        - 1.8.3
        - 1.8.2
        - 1.8.1
        - 1.8.0
        - 1.7.10
        - 1.7.9
        - 1.7.8
        - 1.7.7
        - 1.7.6
    validations:
      required: true

  - type: dropdown
    id: python-version
    attributes:
      label: Python version
      description: Run "bandit --version" if unsure of version number
      options:
        - "3.14 (Default)"
        - "3.13"
        - "3.12"
        - "3.11"
        - "3.10"
        - "3.9"
    validations:
      required: true

  - type: textarea
    id: additional-context
    attributes:
      label: Additional context
      description: Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: ❓ Ask a question
    url: https://github.com/PyCQA/bandit/discussions
    about: Please post questions in discussions.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/build-publish-image.yml
================================================
name: Build and Publish Bandit Images

on:
  release:
    types: [created]
  schedule:
    - cron: '0 0 * * 0' # Every Sunday at midnight
  workflow_dispatch:

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write

    steps:

    - name: Get latest release tag
      if: github.event_name != 'release'
      id: get-latest-tag
      run: |
        TAG=$(curl -s https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .tag_name)
        echo "Latest tag is $TAG"
        echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV

    - name: Check out the repo
      uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
      with:
        ref: ${{ github.event_name == 'release' && github.ref || env.RELEASE_TAG }}

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

    - name: Log in to GitHub Container Registry
      uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Install Cosign
      uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
      with:
        cosign-release: 'v2.2.2'

    - name: Downcase github.repository value
      run: |
        echo "IMAGE_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV}

    - name: Build and push Docker image
      id: build-and-push
      uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
      with:
        context: .
        file: ./docker/Dockerfile
        push: true
        tags: ghcr.io/${{ env.IMAGE_NAME }}/bandit:latest
        platforms: linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v8

    - name: Sign the image
      env:
        TAGS: ghcr.io/${{ env.IMAGE_NAME }}/bandit:latest
        DIGEST: ${{ steps.build-and-push.outputs.digest }}
      run: |
        echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}


================================================
FILE: .github/workflows/dependency-review.yml
================================================
name: 'Dependency Review'
on: [pull_request]

permissions:
  contents: read

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
      - name: 'Dependency Review'
        uses: actions/dependency-review-action@v4


================================================
FILE: .github/workflows/publish-to-pypi.yml
================================================
name: Publish to PyPI

on: workflow_dispatch

jobs:
  build-n-publish:
    name: Build and publish to PyPI
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: this permission is mandatory for trusted publishing
      id-token: write
    steps:
    - uses: actions/checkout@v6
      with:
        fetch-depth: 0
    - name: Set up Python 3.10
      uses: actions/setup-python@v6
      with:
        python-version: "3.10"

    - name: Install dependencies
      run: pip install tox wheel

    - name: Build man page if not present
      run: |
        if [ ! -f doc/build/man/bandit.1 ]; then
          tox run -e manpage
        fi

    - name: Build a binary wheel and a source tarball
      run: |
        python setup.py sdist bdist_wheel

    - name: Publish distribution to PyPI
      if: startsWith(github.ref, 'refs/tags')
      uses: pypa/gh-action-pypi-publish@release/v1


================================================
FILE: .github/workflows/publish-to-test-pypi.yml
================================================
name: Publish to Test PyPI

on: workflow_dispatch

jobs:
  build-n-publish:
    name: Build and publish to Test PyPI
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: this permission is mandatory for trusted publishing
      id-token: write
    steps:
    - uses: actions/checkout@v6
      with:
        fetch-depth: 0
    - name: Set up Python 3.10
      uses: actions/setup-python@v6
      with:
        python-version: "3.10"

    - name: Install dependencies
      run: pip install tox wheel

    - name: Build man page if not present
      run: |
        if [ ! -f doc/build/man/bandit.1 ]; then
          tox run -e manpage
        fi

    - name: Build a binary wheel and a source tarball
      run: |
        python setup.py sdist bdist_wheel

    - name: Publish distribution to Test PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        repository-url: https://test.pypi.org/legacy/


================================================
FILE: .github/workflows/pythonpackage.yml
================================================
name: Build and Test Bandit

on: [push, pull_request]

jobs:
  format:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10"]
    steps:
    - name: Checkout repository
      uses: actions/checkout@v6
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v6
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install tox
    - name: Run tox
      run: tox run -e format

  pep8:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10"]
    steps:
    - name: Checkout repository
      uses: actions/checkout@v6
      with:
        fetch-depth: 2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v6
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install tox
    - name: Run tox
      run: tox run -e pep8

  tests:
    strategy:
      matrix:
        python-version: [
          ["3.10", "310"],
          ["3.11", "311"],
          ["3.12", "312"],
          ["3.13", "313"],
          ["3.14", "314"],
        ]
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    name: ${{ matrix.os }} (${{ matrix.python-version[0] }})
    steps:
    - name: Checkout repository
      uses: actions/checkout@v6
    - name: Set up Python ${{ matrix.python-version[0] }}
      uses: actions/setup-python@v6
      with:
        python-version: ${{ matrix.python-version[0] }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install tox
    - name: Run tox
      run: tox run -e py${{ matrix.python-version[1] }}


================================================
FILE: .gitignore
================================================
env*
venv*
.python-version
*.pyc
.DS_Store
*.egg
*.egg-info
.eggs/
.idea/
.vscode/
.tox
.stestr
build/*
cover/*
.coverage*
doc/build/*
ChangeLog
doc/source/api
.*.sw?
AUTHORS


================================================
FILE: .pre-commit-config.yaml
================================================
exclude: ^(examples|tools|doc)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v6.0.0
  hooks:
  - id: check-yaml
  - id: debug-statements
  - id: end-of-file-fixer
  - id: trailing-whitespace
- repo: https://github.com/asottile/reorder-python-imports
  rev: v3.16.0
  hooks:
  - id: reorder-python-imports
    args: [--application-directories, '.:src', --py38-plus]
- repo: https://github.com/psf/black-pre-commit-mirror
  rev: 25.12.0
  hooks:
  - id: black
    args: [--line-length=79, --target-version=py38]
- repo: https://github.com/asottile/pyupgrade
  rev: v3.21.2
  hooks:
  - id: pyupgrade
    args: [--py38-plus]
- repo: https://github.com/jorisroovers/gitlint
  rev: v0.19.1
  hooks:
  - id: gitlint
#-   repo: https://github.com/pre-commit/mirrors-mypy
#    rev: v0.910-1
#    hooks:
#    -   id: mypy
#        exclude: ^(docs/|example-plugin/)


================================================
FILE: .pre-commit-hooks.yaml
================================================
-   id: bandit
    name: bandit
    description: 'Bandit is a tool for finding common security issues in Python code'
    entry: bandit
    language: python
    language_version: python3
    types: [python]
    require_serial: true


================================================
FILE: .readthedocs.yaml
================================================
version: 2

build:
  os: ubuntu-lts-latest
  tools:
    python: "3.10"

sphinx:
  configuration: doc/source/conf.py

python:
  install:
    - requirements: requirements.txt
    - requirements: doc/requirements.txt
    - method: pip
      path: .
      extra_requirements:
        - sarif


================================================
FILE: .stestr.conf
================================================
[DEFAULT]
test_path=./tests
top_dir=./
parallel_class=True


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at Ian
Stapleton Cordasco <graffatcolmingov@gmail.com>, Ian Lee <IanLee1521@gmail.com>
or Florian Bruhin <me@the-compiler.org>. All complaints will be reviewed and
investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Bandit
Thanks for considering to take part in the improvement of the Bandit project. Contributions are always welcome!
Here are guidelines and rules that can be helpful if you plan to want to get involved in the project.

#### Table Of Contents
[Code of Conduct](#code-of-conduct)

[How Can I Contribute?](#how-can-i-contribute)
  * [Reporting Bugs](#reporting-bugs)
  * [Suggesting Enhancements](#suggesting-enhancements)
  * [Your First Code Contribution](#your-first-code-contribution)
  * [Pull Requests](#pull-requests)
    * [Commit Message Guidelines](#commit-message-guidelines)
    * [Squash Commits](#squash-commits)
  * [Things You Should Know Before Getting Started](#things-you-should-know-before-getting-started)
    * [Vulnerability Tests](#vulnerability-tests)
    * [Writing Tests](#writing-tests)
    * [Extending Bandit](#extending-bandit)

## Code of Conduct
Everyone who participates in this project is governed by the PyCQA [Code of Conduct](https://github.com/PyCQA/bandit/blob/main/CODE_OF_CONDUCT.md#contributor-covenant-code-of-conduct).

## Reporting Bugs
If you encounter a bug, please let us know about it. See the guide here [GitHub issues](https://guides.github.com/features/issues/).

**Before submitting a new issue** you might want to check for an [existing issue](https://github.com/PyCQA/bandit/issues) to know if there is already a reported issue. If an issue is already open please feel free
to add a comment to the existing issue instead of creating a new one.

### Submitting your first issue
We encourage using the issue template to improve quality of reported issues.
Navigate to the issues tab and select `New issue`, then select the **Bug report** template and fill out the form.
To submit a good bug report keep in mind to:
* Use a descriptive title so other people can understand what the issue is about.
* Be specific about the details, for example, what command did you use, what version of Bandit did you use, and in what environment you observed the bug (CI or development).

## Suggesting Enhancements
If you want to suggest an enhancement, open a new issue and use the **Feature request** template.

**Before submitting an enhancement** please check for existing [feature requests](https://github.com/PyCQA/bandit/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement).

Useful things to point out in your feature request:
* Explain your feature request in a way that everyone can understand
* Please try to explain how this feature will improve the Bandit project

## Your First Code Contribution
You can start contributing to Bandit project by picking [bug issues](https://github.com/PyCQA/bandit/issues?q=is%3Aopen+is%3Aissue+label%3Abug)
These issues can be easier to resolve rather than a feature request and can get you up and running with the code base.

## Pull Requests
The best way to get started with Bandit is to grab the source:

Fork the repository into one with your username
```shell script
git clone https://github.com/<your username>/bandit.git
```

Create you own branch to start writing code:
```shell script
git switch -c mybranch
<create local changes>
git add <changed files>
git commit -S
<create a good commit message>
git push origin mybranch
```
You can test any changes with tox:

```shell script
pip install tox
tox run -e pep8
tox run -e format
tox run -e py310
tox run -e docs
tox run -e cover
```
If everything is done, proceed with [opening a new pull request](https://help.github.com/en/desktop/contributing-to-projects/creating-a-pull-request)

### Commit Message Guidelines

We follow the commit formatting recommendations found on [Chris Beams' How to Write a Git Commit Message article](https://chris.beams.io/posts/git-commit/).

Well formed commit messages not only help reviewers understand the nature of
the Pull Request, but also assists the release process where commit messages
are used to generate release notes.

A good example of a commit message would be as follows:

```
Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789
```

Note the `Resolves #123` tag, this references the issue raised and allows us to
ensure issues are associated and closed when a pull request is merged.

Please refer to [the github help page on message types](https://help.github.com/articles/closing-issues-using-keywords/)
for a complete list of issue references.

### Squash Commits

Should your pull request consist of more than one commit (perhaps due to
a change being requested during the review cycle), please perform a git squash
once a reviewer has approved your pull request.

A squash can be performed as follows. Let's say you have the following commits:

    initial commit
    second commit
    final commit

Run the command below with the number set to the total commits you wish to
squash (in our case 3 commits):

    git rebase -i HEAD~3

You default text editor will then open up and you will see the following::

    pick eb36612 initial commit
    pick 9ac8968 second commit
    pick a760569 final commit

    # Rebase eb1429f..a760569 onto eb1429f (3 commands)

We want to rebase on top of our first commit, so we change the other two commits
to `squash`:

    pick eb36612 initial commit
    squash 9ac8968 second commit
    squash a760569 final commit

After this, should you wish to update your commit message to better summarise
all of your pull request, run:

    git commit --amend

You will then need to force push (assuming your initial commit(s) were posted
to github):

    git push origin your-branch --force

## Things You Should Know Before Getting Started

### Vulnerability Tests
Vulnerability tests or "plugins" are defined in files in the plugins directory.

Tests are written in Python and are autodiscovered from the plugins directory.
Each test can examine one or more type of Python statements. Tests are marked
with the types of Python statements they examine (for example: function call,
string, import, etc).

Tests are executed by the ``BanditNodeVisitor`` object as it visits each node
in the AST.

Test results are managed in the ``Manager`` and aggregated for
output at the completion of a test run through the method `output_result` from ``Manager`` instance.

### Writing Tests
To write a test:
 - Identify a vulnerability to build a test for, and create a new file in
   examples/ that contains one or more cases of that vulnerability.
 - Consider the vulnerability you're testing for, mark the function with one
   or more of the appropriate decorators:
   - @checks('Call')
   - @checks('Import', 'ImportFrom')
   - @checks('Str')
 - Create a new Python source file to contain your test, you can reference
   existing tests for examples.
 - The function that you create should take a parameter "context" which is
   an instance of the context class you can query for information about the
   current element being examined.  You can also get the raw AST node for
   more advanced use cases.  Please see the context.py file for more.
 - Extend your Bandit configuration file as needed to support your new test.
 - Execute Bandit against the test file you defined in examples/ and ensure
   that it detects the vulnerability.  Consider variations on how this
   vulnerability might present itself and extend the example file and the test
   function accordingly.


### Extending Bandit

Bandit allows users to write and register extensions for checks and formatters.
Bandit will load plugins from two entry-points:

- `bandit.formatters`
- `bandit.plugins`

Formatters need to accept 5 things:

- `manager`: an instance of `bandit manager`
- `fileobj`: the output file object, which may be sys.stdout
- `sev_level` : Filtering severity level
- `conf_level`: Filtering confidence level
- `lines=-1`: number of lines to report

Plugins tend to take advantage of the `bandit.checks` decorator which allows
the author to register a check for a particular type of AST node. For example

::

    @bandit.checks('Call')
    def prohibit_unsafe_deserialization(context):
        if 'unsafe_load' in context.call_function_name_qual:
            return bandit.Issue(
                severity=bandit.HIGH,
                confidence=bandit.HIGH,
                text="Unsafe deserialization detected."
            )

To register your plugin, you have two options:

1. If you're using setuptools directly, add something like the following to
   your ``setup`` call::

        # If you have an imaginary bson formatter in the bandit_bson module
        # and a function called `formatter`.
        entry_points={'bandit.formatters': ['bson = bandit_bson:formatter']}
        # Or a check for using mako templates in bandit_mako that
        entry_points={'bandit.plugins': ['mako = bandit_mako']}

2. If you're using pbr, add something like the following to your `setup.cfg`
   file::

        [entry_points]
        bandit.formatters =
            bson = bandit_bson:formatter
        bandit.plugins =
            mako = bandit_mako

## Creating and Publishing a Release (Maintainers)

### Create the GitHub Release

1. Navigate to the [Releases](https://github.com/PyCQA/bandit/releases) page
2. Click on `Draft a new release`
3. Under `Choose a tag` enter a new release version (typically increment the patch number) and select `Create new tag: <version> on publish`
4. Click on `Generate release notes`
5. Click on `Publish release`

### Publish the Release to Test PyPI

1. Go to `Actions` tab
2. Click on the `Publish to Test PyPI` action
3. Click on `Run workflow`
4. Select `Use workflow from`, then `Tags` tab, and select `<version>`
5. Click on `Run workflow`

### Publish the Release to PyPI

1. Go to `Actions` tab
2. Click on the `Publish to PyPI` action
3. Click on `Run workflow`
4. Select `Use workflow from`, then `Tags` tab, and select `<version>`
5. Click on `Run workflow`


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.


================================================
FILE: README.rst
================================================
.. image:: https://raw.githubusercontent.com/pycqa/bandit/main/logo/logotype-sm.png
    :alt: Bandit

======

.. image:: https://github.com/PyCQA/bandit/actions/workflows/pythonpackage.yml/badge.svg?branch=main
    :target: https://github.com/PyCQA/bandit/actions?query=workflow%3A%22Build+and+Test+Bandit%22+branch%3Amain
    :alt: Build Status

.. image:: https://readthedocs.org/projects/bandit/badge/?version=latest
    :target: https://readthedocs.org/projects/bandit/
    :alt: Docs Status

.. image:: https://img.shields.io/pypi/v/bandit.svg
    :target: https://pypi.org/project/bandit/
    :alt: Latest Version

.. image:: https://img.shields.io/pypi/pyversions/bandit.svg
    :target: https://pypi.org/project/bandit/
    :alt: Python Versions

.. image:: https://img.shields.io/pypi/format/bandit.svg
    :target: https://pypi.org/project/bandit/
    :alt: Format

.. image:: https://img.shields.io/badge/license-Apache%202-blue.svg
    :target: https://github.com/PyCQA/bandit/blob/main/LICENSE
    :alt: License

.. image:: https://img.shields.io/discord/825463413634891776.svg
    :target: https://discord.gg/qYxpadCgkx
    :alt: Discord

A security linter from PyCQA

* Free software: Apache license
* Documentation: https://bandit.readthedocs.io/en/latest/
* Source: https://github.com/PyCQA/bandit
* Bugs: https://github.com/PyCQA/bandit/issues
* Contributing: https://github.com/PyCQA/bandit/blob/main/CONTRIBUTING.md

Overview
--------

Bandit is a tool designed to find common security issues in Python code. To do
this Bandit processes each file, builds an AST from it, and runs appropriate
plugins against the AST nodes. Once Bandit has finished scanning all the files
it generates a report.

Bandit was originally developed within the OpenStack Security Project and
later rehomed to PyCQA.

.. image:: https://raw.githubusercontent.com/pycqa/bandit/main/bandit-terminal.png
    :alt: Bandit Example Screen Shot

Show Your Style
---------------

.. image:: https://img.shields.io/badge/security-bandit-yellow.svg
    :target: https://github.com/PyCQA/bandit
    :alt: Security Status

Use our badge in your project's README!

using Markdown::

    [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)

using RST::

    .. image:: https://img.shields.io/badge/security-bandit-yellow.svg
        :target: https://github.com/PyCQA/bandit
        :alt: Security Status

References
----------

Python AST module documentation: https://docs.python.org/3/library/ast.html

Green Tree Snakes - the missing Python AST docs:
https://greentreesnakes.readthedocs.org/en/latest/

Documentation of the various types of AST nodes that Bandit currently covers
or could be extended to cover:
https://greentreesnakes.readthedocs.org/en/latest/nodes.html

Container Images
----------------

Bandit is available as a container image, built within the bandit repository
using GitHub Actions. The image is available on ghcr.io:

.. code-block:: console

    docker pull ghcr.io/pycqa/bandit/bandit

The image is built for the following architectures:

* amd64
* arm64
* armv7
* armv8

To pull a specific architecture, use the following format:

.. code-block:: console

    docker pull --platform=<architecture> ghcr.io/pycqa/bandit/bandit:latest

Every image is signed with sigstore cosign and it is possible to verify the
source of origin using the following cosign command:

.. code-block:: console

    cosign verify ghcr.io/pycqa/bandit/bandit:latest \
      --certificate-identity https://github.com/pycqa/bandit/.github/workflows/build-publish-image.yml@refs/tags/<version> \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com

Where `<version>` is the release version of Bandit.

Sponsors
--------

The development of Bandit is made possible by the following sponsors:

.. list-table::
   :width: 100%
   :class: borderless

   * - .. image:: https://avatars.githubusercontent.com/u/34240465?s=200&v=4
          :target: https://opensource.mercedes-benz.com/
          :alt: Mercedes-Benz
          :width: 88

     - .. image:: https://github.githubassets.com/assets/tidelift-8cea37dea8fc.svg
          :target: https://tidelift.com/lifter/search/pypi/bandit
          :alt: Tidelift
          :width: 88

     - .. image:: https://avatars.githubusercontent.com/u/110237746?s=200&v=4
          :target: https://stacklok.com/
          :alt: Stacklok
          :width: 88

If you also ❤️ Bandit, please consider sponsoring.


================================================
FILE: SECURITY.md
================================================
# Security Policy

Bandit is a tool designed to find security issues, so every effort is made that Bandit itself is also
free of those issues. However, if you believe you have found a security vulnerability in this repository
please open it privately via the [Report a security vulnerability](https://github.com/PyCQA/bandit/security/advisories/new) link in the Issues tab.

**Please do not report security vulnerabilities through public issues, discussions, or pull requests.**

Please also inform the [Tidelift security](https://tidelift.com/security). Tidelift will help coordinate the fix and disclosure.


================================================
FILE: bandit/__init__.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
from importlib import metadata

from bandit.core import config  # noqa
from bandit.core import context  # noqa
from bandit.core import manager  # noqa
from bandit.core import meta_ast  # noqa
from bandit.core import node_visitor  # noqa
from bandit.core import test_set  # noqa
from bandit.core import tester  # noqa
from bandit.core import utils  # noqa
from bandit.core.constants import *  # noqa
from bandit.core.issue import *  # noqa
from bandit.core.test_properties import *  # noqa

__author__ = metadata.metadata("bandit")["Author"]
__version__ = metadata.version("bandit")


================================================
FILE: bandit/__main__.py
================================================
#!/usr/bin/env python
# SPDX-License-Identifier: Apache-2.0
"""Bandit is a tool designed to find common security issues in Python code.

Bandit is a tool designed to find common security issues in Python code.
To do this Bandit processes each file, builds an AST from it, and runs
appropriate plugins against the AST nodes. Once Bandit has finished
scanning all the files it generates a report.

Bandit was originally developed within the OpenStack Security Project and
later rehomed to PyCQA.

https://bandit.readthedocs.io/
"""
from bandit.cli import main

main.main()


================================================
FILE: bandit/blacklists/__init__.py
================================================


================================================
FILE: bandit/blacklists/calls.py
================================================
#
# Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
r"""
====================================================
Blacklist various Python calls known to be dangerous
====================================================

This blacklist data checks for a number of Python calls known to have possible
security implications. The following blacklist tests are run against any
function calls encountered in the scanned code base, triggered by encountering
ast.Call nodes.

B301: pickle
------------

Pickle and modules that wrap it can be unsafe when used to
deserialize untrusted data, possible security issue.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B301 | pickle              | - pickle.loads                     | Medium    |
|      |                     | - pickle.load                      |           |
|      |                     | - pickle.Unpickler                 |           |
|      |                     | - dill.loads                       |           |
|      |                     | - dill.load                        |           |
|      |                     | - dill.Unpickler                   |           |
|      |                     | - shelve.open                      |           |
|      |                     | - shelve.DbfilenameShelf           |           |
|      |                     | - jsonpickle.decode                |           |
|      |                     | - jsonpickle.unpickler.decode      |           |
|      |                     | - jsonpickle.unpickler.Unpickler   |           |
|      |                     | - pandas.read_pickle               |           |
+------+---------------------+------------------------------------+-----------+

B302: marshal
-------------

Deserialization with the marshal module is possibly dangerous.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B302 | marshal             | - marshal.load                     | Medium    |
|      |                     | - marshal.loads                    |           |
+------+---------------------+------------------------------------+-----------+

B303: md5
---------

Use of insecure MD2, MD4, MD5, or SHA1 hash function.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B303 | md5                 | - hashlib.md5                      | Medium    |
|      |                     | - hashlib.sha1                     |           |
|      |                     | - Crypto.Hash.MD2.new              |           |
|      |                     | - Crypto.Hash.MD4.new              |           |
|      |                     | - Crypto.Hash.MD5.new              |           |
|      |                     | - Crypto.Hash.SHA.new              |           |
|      |                     | - Cryptodome.Hash.MD2.new          |           |
|      |                     | - Cryptodome.Hash.MD4.new          |           |
|      |                     | - Cryptodome.Hash.MD5.new          |           |
|      |                     | - Cryptodome.Hash.SHA.new          |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .hashes.MD5                      |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .hashes.SHA1                     |           |
+------+---------------------+------------------------------------+-----------+

B304 - B305: ciphers and modes
------------------------------

Use of insecure cipher or cipher mode. Replace with a known secure cipher such
as AES.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B304 | ciphers             | - Crypto.Cipher.ARC2.new           | High      |
|      |                     | - Crypto.Cipher.ARC4.new           |           |
|      |                     | - Crypto.Cipher.Blowfish.new       |           |
|      |                     | - Crypto.Cipher.DES.new            |           |
|      |                     | - Crypto.Cipher.XOR.new            |           |
|      |                     | - Cryptodome.Cipher.ARC2.new       |           |
|      |                     | - Cryptodome.Cipher.ARC4.new       |           |
|      |                     | - Cryptodome.Cipher.Blowfish.new   |           |
|      |                     | - Cryptodome.Cipher.DES.new        |           |
|      |                     | - Cryptodome.Cipher.XOR.new        |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.ARC4         |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.Blowfish     |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.IDEA         |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.CAST5        |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.SEED         |           |
|      |                     | - cryptography.hazmat.primitives   |           |
|      |                     |   .ciphers.algorithms.TripleDES    |           |
+------+---------------------+------------------------------------+-----------+
| B305 | cipher_modes        | - cryptography.hazmat.primitives   | Medium    |
|      |                     |   .ciphers.modes.ECB               |           |
+------+---------------------+------------------------------------+-----------+

B306: mktemp_q
--------------

Use of insecure and deprecated function (mktemp).

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B306 | mktemp_q            | - tempfile.mktemp                  | Medium    |
+------+---------------------+------------------------------------+-----------+

B307: eval
----------

Use of possibly insecure function - consider using safer ast.literal_eval.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B307 | eval                | - eval                             | Medium    |
+------+---------------------+------------------------------------+-----------+

B308: mark_safe
---------------

Use of mark_safe() may expose cross-site scripting vulnerabilities and should
be reviewed.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B308 | mark_safe           | - django.utils.safestring.mark_safe| Medium    |
+------+---------------------+------------------------------------+-----------+

B309: httpsconnection
---------------------

The check for this call has been removed.

Use of HTTPSConnection on older versions of Python prior to 2.7.9 and 3.4.3 do
not provide security, see https://wiki.openstack.org/wiki/OSSN/OSSN-0033

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B309 | httpsconnection     | - httplib.HTTPSConnection          | Medium    |
|      |                     | - http.client.HTTPSConnection      |           |
|      |                     | - six.moves.http_client            |           |
|      |                     |   .HTTPSConnection                 |           |
+------+---------------------+------------------------------------+-----------+

B310: urllib_urlopen
--------------------

Audit url open for permitted schemes. Allowing use of 'file:'' or custom
schemes is often unexpected.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B310 | urllib_urlopen      | - urllib.urlopen                   | Medium    |
|      |                     | - urllib.request.urlopen           |           |
|      |                     | - urllib.urlretrieve               |           |
|      |                     | - urllib.request.urlretrieve       |           |
|      |                     | - urllib.URLopener                 |           |
|      |                     | - urllib.request.URLopener         |           |
|      |                     | - urllib.FancyURLopener            |           |
|      |                     | - urllib.request.FancyURLopener    |           |
|      |                     | - urllib2.urlopen                  |           |
|      |                     | - urllib2.Request                  |           |
|      |                     | - six.moves.urllib.request.urlopen |           |
|      |                     | - six.moves.urllib.request         |           |
|      |                     |   .urlretrieve                     |           |
|      |                     | - six.moves.urllib.request         |           |
|      |                     |   .URLopener                       |           |
|      |                     | - six.moves.urllib.request         |           |
|      |                     |   .FancyURLopener                  |           |
+------+---------------------+------------------------------------+-----------+

B311: random
------------

Standard pseudo-random generators are not suitable for security/cryptographic
purposes. Consider using the secrets module instead:
https://docs.python.org/library/secrets.html

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B311 | random              | - random.Random                    | Low       |
|      |                     | - random.random                    |           |
|      |                     | - random.randrange                 |           |
|      |                     | - random.randint                   |           |
|      |                     | - random.choice                    |           |
|      |                     | - random.choices                   |           |
|      |                     | - random.uniform                   |           |
|      |                     | - random.triangular                |           |
|      |                     | - random.randbytes                 |           |
|      |                     | - random.randrange                 |           |
|      |                     | - random.sample                    |           |
|      |                     | - random.getrandbits               |           |
+------+---------------------+------------------------------------+-----------+

B312: telnetlib
---------------

Telnet-related functions are being called. Telnet is considered insecure. Use
SSH or some other encrypted protocol.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B312 | telnetlib           | - telnetlib.\*                     | High      |
+------+---------------------+------------------------------------+-----------+

B313 - B319: XML
----------------

Most of this is based off of Christian Heimes' work on defusedxml:
https://pypi.org/project/defusedxml/#defusedxml-sax

Using various XLM methods to parse untrusted XML data is known to be vulnerable
to XML attacks. Methods should be replaced with their defusedxml equivalents.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B313 | xml_bad_cElementTree| - xml.etree.cElementTree.parse     | Medium    |
|      |                     | - xml.etree.cElementTree.iterparse |           |
|      |                     | - xml.etree.cElementTree.fromstring|           |
|      |                     | - xml.etree.cElementTree.XMLParser |           |
+------+---------------------+------------------------------------+-----------+
| B314 | xml_bad_ElementTree | - xml.etree.ElementTree.parse      | Medium    |
|      |                     | - xml.etree.ElementTree.iterparse  |           |
|      |                     | - xml.etree.ElementTree.fromstring |           |
|      |                     | - xml.etree.ElementTree.XMLParser  |           |
+------+---------------------+------------------------------------+-----------+
| B315 | xml_bad_expatreader | - xml.sax.expatreader.create_parser| Medium    |
+------+---------------------+------------------------------------+-----------+
| B316 | xml_bad_expatbuilder| - xml.dom.expatbuilder.parse       | Medium    |
|      |                     | - xml.dom.expatbuilder.parseString |           |
+------+---------------------+------------------------------------+-----------+
| B317 | xml_bad_sax         | - xml.sax.parse                    | Medium    |
|      |                     | - xml.sax.parseString              |           |
|      |                     | - xml.sax.make_parser              |           |
+------+---------------------+------------------------------------+-----------+
| B318 | xml_bad_minidom     | - xml.dom.minidom.parse            | Medium    |
|      |                     | - xml.dom.minidom.parseString      |           |
+------+---------------------+------------------------------------+-----------+
| B319 | xml_bad_pulldom     | - xml.dom.pulldom.parse            | Medium    |
|      |                     | - xml.dom.pulldom.parseString      |           |
+------+---------------------+------------------------------------+-----------+

B320: xml_bad_etree
-------------------

The check for this call has been removed.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B320 | xml_bad_etree       | - lxml.etree.parse                 | Medium    |
|      |                     | - lxml.etree.fromstring            |           |
|      |                     | - lxml.etree.RestrictedElement     |           |
|      |                     | - lxml.etree.GlobalParserTLS       |           |
|      |                     | - lxml.etree.getDefaultParser      |           |
|      |                     | - lxml.etree.check_docinfo         |           |
+------+---------------------+------------------------------------+-----------+

B321: ftplib
------------

FTP-related functions are being called. FTP is considered insecure. Use
SSH/SFTP/SCP or some other encrypted protocol.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B321 | ftplib              | - ftplib.\*                        | High      |
+------+---------------------+------------------------------------+-----------+

B322: input
-----------

The check for this call has been removed.

The input method in Python 2 will read from standard input, evaluate and
run the resulting string as python source code. This is similar, though in
many ways worse, than using eval. On Python 2, use raw_input instead, input
is safe in Python 3.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B322 | input               | - input                            | High      |
+------+---------------------+------------------------------------+-----------+

B323: unverified_context
------------------------

By default, Python will create a secure, verified ssl context for use in such
classes as HTTPSConnection. However, it still allows using an insecure
context via the _create_unverified_context that reverts to the previous
behavior that does not validate certificates or perform hostname checks.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B323 | unverified_context  | - ssl._create_unverified_context   | Medium    |
+------+---------------------+------------------------------------+-----------+

B325: tempnam
--------------

The check for this call has been removed.

Use of os.tempnam() and os.tmpnam() is vulnerable to symlink attacks. Consider
using tmpfile() instead.

For further information:
    https://docs.python.org/2.7/library/os.html#os.tempnam
    https://docs.python.org/3/whatsnew/3.0.html?highlight=tempnam
    https://bugs.python.org/issue17880

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Calls                             |  Severity |
+======+=====================+====================================+===========+
| B325 | tempnam             | - os.tempnam                       | Medium    |
|      |                     | - os.tmpnam                        |           |
+------+---------------------+------------------------------------+-----------+

"""
from bandit.blacklists import utils
from bandit.core import issue


def gen_blacklist():
    """Generate a list of items to blacklist.

    Methods of this type, "bandit.blacklist" plugins, are used to build a list
    of items that bandit's built in blacklisting tests will use to trigger
    issues. They replace the older blacklist* test plugins and allow
    blacklisted items to have a unique bandit ID for filtering and profile
    usage.

    :return: a dictionary mapping node types to a list of blacklist data
    """
    sets = []
    sets.append(
        utils.build_conf_dict(
            "pickle",
            "B301",
            issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA,
            [
                "pickle.loads",
                "pickle.load",
                "pickle.Unpickler",
                "dill.loads",
                "dill.load",
                "dill.Unpickler",
                "shelve.open",
                "shelve.DbfilenameShelf",
                "jsonpickle.decode",
                "jsonpickle.unpickler.decode",
                "jsonpickle.unpickler.Unpickler",
                "pandas.read_pickle",
            ],
            "Pickle and modules that wrap it can be unsafe when used to "
            "deserialize untrusted data, possible security issue.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "marshal",
            "B302",
            issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA,
            ["marshal.load", "marshal.loads"],
            "Deserialization with the marshal module is possibly dangerous.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "md5",
            "B303",
            issue.Cwe.BROKEN_CRYPTO,
            [
                "Crypto.Hash.MD2.new",
                "Crypto.Hash.MD4.new",
                "Crypto.Hash.MD5.new",
                "Crypto.Hash.SHA.new",
                "Cryptodome.Hash.MD2.new",
                "Cryptodome.Hash.MD4.new",
                "Cryptodome.Hash.MD5.new",
                "Cryptodome.Hash.SHA.new",
                "cryptography.hazmat.primitives.hashes.MD5",
                "cryptography.hazmat.primitives.hashes.SHA1",
            ],
            "Use of insecure MD2, MD4, MD5, or SHA1 hash function.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "ciphers",
            "B304",
            issue.Cwe.BROKEN_CRYPTO,
            [
                "Crypto.Cipher.ARC2.new",
                "Crypto.Cipher.ARC4.new",
                "Crypto.Cipher.Blowfish.new",
                "Crypto.Cipher.DES.new",
                "Crypto.Cipher.XOR.new",
                "Cryptodome.Cipher.ARC2.new",
                "Cryptodome.Cipher.ARC4.new",
                "Cryptodome.Cipher.Blowfish.new",
                "Cryptodome.Cipher.DES.new",
                "Cryptodome.Cipher.XOR.new",
                "cryptography.hazmat.primitives.ciphers.algorithms.ARC4",
                "cryptography.hazmat.primitives.ciphers.algorithms.Blowfish",
                "cryptography.hazmat.primitives.ciphers.algorithms.CAST5",
                "cryptography.hazmat.primitives.ciphers.algorithms.IDEA",
                "cryptography.hazmat.primitives.ciphers.algorithms.SEED",
                "cryptography.hazmat.primitives.ciphers.algorithms.TripleDES",
            ],
            "Use of insecure cipher {name}. Replace with a known secure"
            " cipher such as AES.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "cipher_modes",
            "B305",
            issue.Cwe.BROKEN_CRYPTO,
            ["cryptography.hazmat.primitives.ciphers.modes.ECB"],
            "Use of insecure cipher mode {name}.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "mktemp_q",
            "B306",
            issue.Cwe.INSECURE_TEMP_FILE,
            ["tempfile.mktemp"],
            "Use of insecure and deprecated function (mktemp).",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "eval",
            "B307",
            issue.Cwe.OS_COMMAND_INJECTION,
            ["eval"],
            "Use of possibly insecure function - consider using safer "
            "ast.literal_eval.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "mark_safe",
            "B308",
            issue.Cwe.XSS,
            ["django.utils.safestring.mark_safe"],
            "Use of mark_safe() may expose cross-site scripting "
            "vulnerabilities and should be reviewed.",
        )
    )

    # skipped B309 as the check for a call to httpsconnection has been removed

    sets.append(
        utils.build_conf_dict(
            "urllib_urlopen",
            "B310",
            issue.Cwe.PATH_TRAVERSAL,
            [
                "urllib.request.urlopen",
                "urllib.request.urlretrieve",
                "urllib.request.URLopener",
                "urllib.request.FancyURLopener",
                "six.moves.urllib.request.urlopen",
                "six.moves.urllib.request.urlretrieve",
                "six.moves.urllib.request.URLopener",
                "six.moves.urllib.request.FancyURLopener",
            ],
            "Audit url open for permitted schemes. Allowing use of file:/ or "
            "custom schemes is often unexpected.",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "random",
            "B311",
            issue.Cwe.INSUFFICIENT_RANDOM_VALUES,
            [
                "random.Random",
                "random.random",
                "random.randrange",
                "random.randint",
                "random.choice",
                "random.choices",
                "random.uniform",
                "random.triangular",
                "random.randbytes",
                "random.sample",
                "random.randrange",
                "random.getrandbits",
            ],
            "Standard pseudo-random generators are not suitable for "
            "security/cryptographic purposes.",
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "telnetlib",
            "B312",
            issue.Cwe.CLEARTEXT_TRANSMISSION,
            ["telnetlib.Telnet"],
            "Telnet-related functions are being called. Telnet is considered "
            "insecure. Use SSH or some other encrypted protocol.",
            "HIGH",
        )
    )

    # Most of this is based off of Christian Heimes' work on defusedxml:
    #   https://pypi.org/project/defusedxml/#defusedxml-sax

    xml_msg = (
        "Using {name} to parse untrusted XML data is known to be "
        "vulnerable to XML attacks. Replace {name} with its "
        "defusedxml equivalent function or make sure "
        "defusedxml.defuse_stdlib() is called"
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_cElementTree",
            "B313",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            [
                "xml.etree.cElementTree.parse",
                "xml.etree.cElementTree.iterparse",
                "xml.etree.cElementTree.fromstring",
                "xml.etree.cElementTree.XMLParser",
            ],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_ElementTree",
            "B314",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            [
                "xml.etree.ElementTree.parse",
                "xml.etree.ElementTree.iterparse",
                "xml.etree.ElementTree.fromstring",
                "xml.etree.ElementTree.XMLParser",
            ],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_expatreader",
            "B315",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.sax.expatreader.create_parser"],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_expatbuilder",
            "B316",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.expatbuilder.parse", "xml.dom.expatbuilder.parseString"],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_sax",
            "B317",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.sax.parse", "xml.sax.parseString", "xml.sax.make_parser"],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_minidom",
            "B318",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.minidom.parse", "xml.dom.minidom.parseString"],
            xml_msg,
        )
    )

    sets.append(
        utils.build_conf_dict(
            "xml_bad_pulldom",
            "B319",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.pulldom.parse", "xml.dom.pulldom.parseString"],
            xml_msg,
        )
    )

    # skipped B320 as the check for a call to lxml.etree has been removed

    # end of XML tests

    sets.append(
        utils.build_conf_dict(
            "ftplib",
            "B321",
            issue.Cwe.CLEARTEXT_TRANSMISSION,
            ["ftplib.FTP"],
            "FTP-related functions are being called. FTP is considered "
            "insecure. Use SSH/SFTP/SCP or some other encrypted protocol.",
            "HIGH",
        )
    )

    # skipped B322 as the check for a call to input() has been removed

    sets.append(
        utils.build_conf_dict(
            "unverified_context",
            "B323",
            issue.Cwe.IMPROPER_CERT_VALIDATION,
            ["ssl._create_unverified_context"],
            "By default, Python will create a secure, verified ssl context for"
            " use in such classes as HTTPSConnection. However, it still allows"
            " using an insecure context via the _create_unverified_context "
            "that  reverts to the previous behavior that does not validate "
            "certificates or perform hostname checks.",
        )
    )

    # skipped B324 (used in bandit/plugins/hashlib_new_insecure_functions.py)

    # skipped B325 as the check for a call to os.tempnam and os.tmpnam have
    # been removed

    return {"Call": sets}


================================================
FILE: bandit/blacklists/imports.py
================================================
#
# Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
r"""
======================================================
Blacklist various Python imports known to be dangerous
======================================================

This blacklist data checks for a number of Python modules known to have
possible security implications. The following blacklist tests are run against
any import statements or calls encountered in the scanned code base.

Note that the XML rules listed here are mostly based off of Christian Heimes'
work on defusedxml: https://pypi.org/project/defusedxml/

B401: import_telnetlib
----------------------

A telnet-related module is being imported. Telnet is considered insecure. Use
SSH or some other encrypted protocol.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B401 | import_telnetlib    | - telnetlib                        | high      |
+------+---------------------+------------------------------------+-----------+

B402: import_ftplib
-------------------
A FTP-related module is being imported.  FTP is considered insecure. Use
SSH/SFTP/SCP or some other encrypted protocol.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B402 | import_ftplib       | - ftplib                           | high      |
+------+---------------------+------------------------------------+-----------+

B403: import_pickle
-------------------

Consider possible security implications associated with these modules.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B403 | import_pickle       | - pickle                           | low       |
|      |                     | - cPickle                          |           |
|      |                     | - dill                             |           |
|      |                     | - shelve                           |           |
+------+---------------------+------------------------------------+-----------+

B404: import_subprocess
-----------------------

Consider possible security implications associated with these modules.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B404 | import_subprocess   | - subprocess                       | low       |
+------+---------------------+------------------------------------+-----------+


B405: import_xml_etree
----------------------

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package,
or make sure defusedxml.defuse_stdlib() is called.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B405 | import_xml_etree    | - xml.etree.cElementTree           | low       |
|      |                     | - xml.etree.ElementTree            |           |
+------+---------------------+------------------------------------+-----------+

B406: import_xml_sax
--------------------

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package,
or make sure defusedxml.defuse_stdlib() is called.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B406 | import_xml_sax      | - xml.sax                          | low       |
+------+---------------------+------------------------------------+-----------+

B407: import_xml_expat
----------------------

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package,
or make sure defusedxml.defuse_stdlib() is called.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B407 | import_xml_expat    | - xml.dom.expatbuilder             | low       |
+------+---------------------+------------------------------------+-----------+

B408: import_xml_minidom
------------------------

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package,
or make sure defusedxml.defuse_stdlib() is called.


+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B408 | import_xml_minidom  | - xml.dom.minidom                  | low       |
+------+---------------------+------------------------------------+-----------+

B409: import_xml_pulldom
------------------------

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package,
or make sure defusedxml.defuse_stdlib() is called.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B409 | import_xml_pulldom  | - xml.dom.pulldom                  | low       |
+------+---------------------+------------------------------------+-----------+

B410: import_lxml
-----------------

This import blacklist has been removed. The information here has been
left for historical purposes.

Using various methods to parse untrusted XML data is known to be vulnerable to
XML attacks. Replace vulnerable imports with the equivalent defusedxml package.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B410 | import_lxml         | - lxml                             | low       |
+------+---------------------+------------------------------------+-----------+

B411: import_xmlrpclib
----------------------

XMLRPC is particularly dangerous as it is also concerned with communicating
data over a network. Use defusedxml.xmlrpc.monkey_patch() function to
monkey-patch xmlrpclib and mitigate remote XML attacks.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B411 | import_xmlrpclib    | - xmlrpc                           | high      |
+------+---------------------+------------------------------------+-----------+

B412: import_httpoxy
--------------------
httpoxy is a set of vulnerabilities that affect application code running in
CGI, or CGI-like environments. The use of CGI for web applications should be
avoided to prevent this class of attack. More details are available
at https://httpoxy.org/.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B412 | import_httpoxy      | - wsgiref.handlers.CGIHandler      | high      |
|      |                     | - twisted.web.twcgi.CGIScript      |           |
+------+---------------------+------------------------------------+-----------+

B413: import_pycrypto
---------------------
pycrypto library is known to have publicly disclosed buffer overflow
vulnerability https://github.com/dlitz/pycrypto/issues/176. It is no longer
actively maintained and has been deprecated in favor of pyca/cryptography
library.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B413 | import_pycrypto     | - Crypto.Cipher                    | high      |
|      |                     | - Crypto.Hash                      |           |
|      |                     | - Crypto.IO                        |           |
|      |                     | - Crypto.Protocol                  |           |
|      |                     | - Crypto.PublicKey                 |           |
|      |                     | - Crypto.Random                    |           |
|      |                     | - Crypto.Signature                 |           |
|      |                     | - Crypto.Util                      |           |
+------+---------------------+------------------------------------+-----------+

B414: import_pycryptodome
-------------------------
This import blacklist has been removed. The information here has been
left for historical purposes.

pycryptodome is a direct fork of pycrypto that has not fully addressed
the issues inherent in PyCrypto.  It seems to exist, mainly, as an API
compatible continuation of pycrypto and should be deprecated in favor
of pyca/cryptography which has more support among the Python community.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B414 | import_pycryptodome | - Cryptodome.Cipher                | high      |
|      |                     | - Cryptodome.Hash                  |           |
|      |                     | - Cryptodome.IO                    |           |
|      |                     | - Cryptodome.Protocol              |           |
|      |                     | - Cryptodome.PublicKey             |           |
|      |                     | - Cryptodome.Random                |           |
|      |                     | - Cryptodome.Signature             |           |
|      |                     | - Cryptodome.Util                  |           |
+------+---------------------+------------------------------------+-----------+

B415: import_pyghmi
-------------------
An IPMI-related module is being imported. IPMI is considered insecure. Use
an encrypted protocol.

+------+---------------------+------------------------------------+-----------+
| ID   |  Name               |  Imports                           |  Severity |
+======+=====================+====================================+===========+
| B415 | import_pyghmi       | - pyghmi                           | high      |
+------+---------------------+------------------------------------+-----------+

"""
from bandit.blacklists import utils
from bandit.core import issue


def gen_blacklist():
    """Generate a list of items to blacklist.

    Methods of this type, "bandit.blacklist" plugins, are used to build a list
    of items that bandit's built in blacklisting tests will use to trigger
    issues. They replace the older blacklist* test plugins and allow
    blacklisted items to have a unique bandit ID for filtering and profile
    usage.

    :return: a dictionary mapping node types to a list of blacklist data
    """
    sets = []
    sets.append(
        utils.build_conf_dict(
            "import_telnetlib",
            "B401",
            issue.Cwe.CLEARTEXT_TRANSMISSION,
            ["telnetlib"],
            "A telnet-related module is being imported.  Telnet is "
            "considered insecure. Use SSH or some other encrypted protocol.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_ftplib",
            "B402",
            issue.Cwe.CLEARTEXT_TRANSMISSION,
            ["ftplib"],
            "A FTP-related module is being imported.  FTP is considered "
            "insecure. Use SSH/SFTP/SCP or some other encrypted protocol.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_pickle",
            "B403",
            issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA,
            ["pickle", "cPickle", "dill", "shelve"],
            "Consider possible security implications associated with "
            "{name} module.",
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_subprocess",
            "B404",
            issue.Cwe.OS_COMMAND_INJECTION,
            ["subprocess"],
            "Consider possible security implications associated with the "
            "subprocess module.",
            "LOW",
        )
    )

    # Most of this is based off of Christian Heimes' work on defusedxml:
    #   https://pypi.org/project/defusedxml/#defusedxml-sax

    xml_msg = (
        "Using {name} to parse untrusted XML data is known to be "
        "vulnerable to XML attacks. Replace {name} with the equivalent "
        "defusedxml package, or make sure defusedxml.defuse_stdlib() "
        "is called."
    )

    sets.append(
        utils.build_conf_dict(
            "import_xml_etree",
            "B405",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.etree.cElementTree", "xml.etree.ElementTree"],
            xml_msg,
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_xml_sax",
            "B406",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.sax"],
            xml_msg,
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_xml_expat",
            "B407",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.expatbuilder"],
            xml_msg,
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_xml_minidom",
            "B408",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.minidom"],
            xml_msg,
            "LOW",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_xml_pulldom",
            "B409",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xml.dom.pulldom"],
            xml_msg,
            "LOW",
        )
    )

    # skipped B410 as the check for import_lxml has been removed

    sets.append(
        utils.build_conf_dict(
            "import_xmlrpclib",
            "B411",
            issue.Cwe.IMPROPER_INPUT_VALIDATION,
            ["xmlrpc"],
            "Using {name} to parse untrusted XML data is known to be "
            "vulnerable to XML attacks. Use defusedxml.xmlrpc.monkey_patch() "
            "function to monkey-patch xmlrpclib and mitigate XML "
            "vulnerabilities.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_httpoxy",
            "B412",
            issue.Cwe.IMPROPER_ACCESS_CONTROL,
            [
                "wsgiref.handlers.CGIHandler",
                "twisted.web.twcgi.CGIScript",
                "twisted.web.twcgi.CGIDirectory",
            ],
            "Consider possible security implications associated with "
            "{name} module.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_pycrypto",
            "B413",
            issue.Cwe.BROKEN_CRYPTO,
            [
                "Crypto.Cipher",
                "Crypto.Hash",
                "Crypto.IO",
                "Crypto.Protocol",
                "Crypto.PublicKey",
                "Crypto.Random",
                "Crypto.Signature",
                "Crypto.Util",
            ],
            "The pyCrypto library and its module {name} are no longer actively"
            " maintained and have been deprecated. "
            "Consider using pyca/cryptography library.",
            "HIGH",
        )
    )

    sets.append(
        utils.build_conf_dict(
            "import_pyghmi",
            "B415",
            issue.Cwe.CLEARTEXT_TRANSMISSION,
            ["pyghmi"],
            "An IPMI-related module is being imported. IPMI is considered "
            "insecure. Use an encrypted protocol.",
            "HIGH",
        )
    )

    return {"Import": sets, "ImportFrom": sets, "Call": sets}


================================================
FILE: bandit/blacklists/utils.py
================================================
#
# Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
r"""Utils module."""


def build_conf_dict(name, bid, cwe, qualnames, message, level="MEDIUM"):
    """Build and return a blacklist configuration dict."""
    return {
        "name": name,
        "id": bid,
        "cwe": cwe,
        "message": message,
        "qualnames": qualnames,
        "level": level,
    }


================================================
FILE: bandit/cli/__init__.py
================================================


================================================
FILE: bandit/cli/baseline.py
================================================
#
# Copyright 2015 Hewlett-Packard Enterprise
#
# SPDX-License-Identifier: Apache-2.0
# #############################################################################
# Bandit Baseline is a tool that runs Bandit against a Git commit, and compares
# the current commit findings to the parent commit findings.
# To do this it checks out the parent commit, runs Bandit (with any provided
# filters or profiles), checks out the current commit, runs Bandit, and then
# reports on any new findings.
# #############################################################################
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import contextlib
import logging
import os
import shutil
import subprocess  # nosec: B404
import sys
import tempfile

try:
    import git
except ImportError:
    git = None

bandit_args = sys.argv[1:]
baseline_tmp_file = "_bandit_baseline_run.json_"
current_commit = None
default_output_format = "terminal"
LOG = logging.getLogger(__name__)
repo = None
report_basename = "bandit_baseline_result"
valid_baseline_formats = ["txt", "html", "json"]

"""baseline.py"""


def main():
    """Execute Bandit."""
    # our cleanup function needs this and can't be passed arguments
    global current_commit
    global repo

    parent_commit = None
    output_format = None
    repo = None
    report_fname = None

    init_logger()

    output_format, repo, report_fname = initialize()

    if not repo:
        sys.exit(2)

    # #################### Find current and parent commits ####################
    try:
        commit = repo.commit()
        current_commit = commit.hexsha
        LOG.info("Got current commit: [%s]", commit.name_rev)

        commit = commit.parents[0]
        parent_commit = commit.hexsha
        LOG.info("Got parent commit: [%s]", commit.name_rev)

    except git.GitCommandError:
        LOG.error("Unable to get current or parent commit")
        sys.exit(2)
    except IndexError:
        LOG.error("Parent commit not available")
        sys.exit(2)

    # #################### Run Bandit against both commits ####################
    output_type = (
        ["-f", "txt"]
        if output_format == default_output_format
        else ["-o", report_fname]
    )

    with baseline_setup() as t:
        bandit_tmpfile = f"{t}/{baseline_tmp_file}"

        steps = [
            {
                "message": "Getting Bandit baseline results",
                "commit": parent_commit,
                "args": bandit_args + ["-f", "json", "-o", bandit_tmpfile],
            },
            {
                "message": "Comparing Bandit results to baseline",
                "commit": current_commit,
                "args": bandit_args + ["-b", bandit_tmpfile] + output_type,
            },
        ]

        return_code = None

        for step in steps:
            repo.head.reset(commit=step["commit"], working_tree=True)

            LOG.info(step["message"])

            bandit_command = ["bandit"] + step["args"]

            try:
                output = subprocess.check_output(bandit_command)  # nosec: B603
            except subprocess.CalledProcessError as e:
                output = e.output
                return_code = e.returncode
            else:
                return_code = 0
                output = output.decode("utf-8")  # subprocess returns bytes

            if return_code not in [0, 1]:
                LOG.error(
                    "Error running command: %s\nOutput: %s\n",
                    bandit_args,
                    output,
                )

    # #################### Output and exit ####################################
    # print output or display message about written report
    if output_format == default_output_format:
        print(output)
    else:
        LOG.info("Successfully wrote %s", report_fname)

    # exit with the code the last Bandit run returned
    sys.exit(return_code)


# #################### Clean up before exit ###################################
@contextlib.contextmanager
def baseline_setup():
    """Baseline setup by creating temp folder and resetting repo."""
    d = tempfile.mkdtemp()
    yield d
    shutil.rmtree(d, True)

    if repo:
        repo.head.reset(commit=current_commit, working_tree=True)


# #################### Setup logging ##########################################
def init_logger():
    """Init logger."""
    LOG.handlers = []
    log_level = logging.INFO
    log_format_string = "[%(levelname)7s ] %(message)s"
    logging.captureWarnings(True)
    LOG.setLevel(log_level)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter(log_format_string))
    LOG.addHandler(handler)


# #################### Perform initialization and validate assumptions ########
def initialize():
    """Initialize arguments and output formats."""
    valid = True

    # #################### Parse Args #########################################
    parser = argparse.ArgumentParser(
        description="Bandit Baseline - Generates Bandit results compared to "
        "a baseline",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="Additional Bandit arguments such as severity filtering (-ll) "
        "can be added and will be passed to Bandit.",
    )
    if sys.version_info >= (3, 14):
        parser.suggest_on_error = True
        parser.color = False

    parser.add_argument(
        "targets",
        metavar="targets",
        type=str,
        nargs="+",
        help="source file(s) or directory(s) to be tested",
    )

    parser.add_argument(
        "-f",
        dest="output_format",
        action="store",
        default="terminal",
        help="specify output format",
        choices=valid_baseline_formats,
    )

    args, _ = parser.parse_known_args()

    # #################### Setup Output #######################################
    # set the output format, or use a default if not provided
    output_format = (
        args.output_format if args.output_format else default_output_format
    )

    if output_format == default_output_format:
        LOG.info("No output format specified, using %s", default_output_format)

    # set the report name based on the output format
    report_fname = f"{report_basename}.{output_format}"

    # #################### Check Requirements #################################
    if git is None:
        LOG.error("Git not available, reinstall with baseline extra")
        valid = False
        return (None, None, None)

    try:
        repo = git.Repo(os.getcwd())

    except git.exc.InvalidGitRepositoryError:
        LOG.error("Bandit baseline must be called from a git project root")
        valid = False

    except git.exc.GitCommandNotFound:
        LOG.error("Git command not found")
        valid = False

    else:
        if repo.is_dirty():
            LOG.error(
                "Current working directory is dirty and must be " "resolved"
            )
            valid = False

    # if output format is specified, we need to be able to write the report
    if output_format != default_output_format and os.path.exists(report_fname):
        LOG.error("File %s already exists, aborting", report_fname)
        valid = False

    # Bandit needs to be able to create this temp file
    if os.path.exists(baseline_tmp_file):
        LOG.error(
            "Temporary file %s needs to be removed prior to running",
            baseline_tmp_file,
        )
        valid = False

    # we must validate -o is not provided, as it will mess up Bandit baseline
    if "-o" in bandit_args:
        LOG.error("Bandit baseline must not be called with the -o option")
        valid = False

    return (output_format, repo, report_fname) if valid else (None, None, None)


if __name__ == "__main__":
    main()


================================================
FILE: bandit/cli/config_generator.py
================================================
# Copyright 2015 Red Hat Inc.
#
# SPDX-License-Identifier: Apache-2.0
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import importlib
import logging
import os
import sys

import yaml

from bandit.core import extension_loader

PROG_NAME = "bandit_conf_generator"
LOG = logging.getLogger(__name__)


template = """
### Bandit config file generated from:
# '{cli}'

### This config may optionally select a subset of tests to run or skip by
### filling out the 'tests' and 'skips' lists given below. If no tests are
### specified for inclusion then it is assumed all tests are desired. The skips
### set will remove specific tests from the include set. This can be controlled
### using the -t/-s CLI options. Note that the same test ID should not appear
### in both 'tests' and 'skips', this would be nonsensical and is detected by
### Bandit at runtime.

# Available tests:
{test_list}

# (optional) list included test IDs here, eg '[B101, B406]':
{test}

# (optional) list skipped test IDs here, eg '[B101, B406]':
{skip}

### (optional) plugin settings - some test plugins require configuration data
### that may be given here, per-plugin. All bandit test plugins have a built in
### set of sensible defaults and these will be used if no configuration is
### provided. It is not necessary to provide settings for every (or any) plugin
### if the defaults are acceptable.

{settings}
"""


def init_logger():
    """Init logger."""
    LOG.handlers = []
    log_level = logging.INFO
    log_format_string = "[%(levelname)5s]: %(message)s"
    logging.captureWarnings(True)
    LOG.setLevel(log_level)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter(log_format_string))
    LOG.addHandler(handler)


def parse_args():
    """Parse arguments."""
    help_description = """Bandit Config Generator

    This tool is used to generate an optional profile.  The profile may be used
    to include or skip tests and override values for plugins.

    When used to store an output profile, this tool will output a template that
    includes all plugins and their default settings.  Any settings which aren't
    being overridden can be safely removed from the profile and default values
    will be used.  Bandit will prefer settings from the profile over the built
    in values."""

    parser = argparse.ArgumentParser(
        description=help_description,
        formatter_class=argparse.RawTextHelpFormatter,
    )
    if sys.version_info >= (3, 14):
        parser.suggest_on_error = True
        parser.color = False

    parser.add_argument(
        "--show-defaults",
        dest="show_defaults",
        action="store_true",
        help="show the default settings values for each "
        "plugin but do not output a profile",
    )
    parser.add_argument(
        "-o",
        "--out",
        dest="output_file",
        action="store",
        help="output file to save profile",
    )
    parser.add_argument(
        "-t",
        "--tests",
        dest="tests",
        action="store",
        default=None,
        type=str,
        help="list of test names to run",
    )
    parser.add_argument(
        "-s",
        "--skip",
        dest="skips",
        action="store",
        default=None,
        type=str,
        help="list of test names to skip",
    )
    args = parser.parse_args()

    if not args.output_file and not args.show_defaults:
        parser.print_help()
        parser.exit(1)

    return args


def get_config_settings():
    """Get configuration settings."""
    config = {}
    for plugin in extension_loader.MANAGER.plugins:
        fn_name = plugin.name
        function = plugin.plugin

        # if a function takes config...
        if hasattr(function, "_takes_config"):
            fn_module = importlib.import_module(function.__module__)

            # call the config generator if it exists
            if hasattr(fn_module, "gen_config"):
                config[fn_name] = fn_module.gen_config(function._takes_config)

    return yaml.safe_dump(config, default_flow_style=False)


def main():
    """Config generator to write configuration file."""
    init_logger()
    args = parse_args()

    yaml_settings = get_config_settings()

    if args.show_defaults:
        print(yaml_settings)

    if args.output_file:
        if os.path.exists(os.path.abspath(args.output_file)):
            LOG.error("File %s already exists, exiting", args.output_file)
            sys.exit(2)

        try:
            with open(args.output_file, "w") as f:
                skips = args.skips.split(",") if args.skips else []
                tests = args.tests.split(",") if args.tests else []

                for skip in skips:
                    if not extension_loader.MANAGER.check_id(skip):
                        raise RuntimeError(f"unknown ID in skips: {skip}")

                for test in tests:
                    if not extension_loader.MANAGER.check_id(test):
                        raise RuntimeError(f"unknown ID in tests: {test}")

                tpl = "# {0} : {1}"
                test_list = [
                    tpl.format(t.plugin._test_id, t.name)
                    for t in extension_loader.MANAGER.plugins
                ]

                others = [
                    tpl.format(k, v["name"])
                    for k, v in (
                        extension_loader.MANAGER.blacklist_by_id.items()
                    )
                ]
                test_list.extend(others)
                test_list.sort()

                contents = template.format(
                    cli=" ".join(sys.argv),
                    settings=yaml_settings,
                    test_list="\n".join(test_list),
                    skip="skips: " + str(skips) if skips else "skips:",
                    test="tests: " + str(tests) if tests else "tests:",
                )
                f.write(contents)

        except OSError:
            LOG.error("Unable to open %s for writing", args.output_file)

        except Exception as e:
            LOG.error("Error: %s", e)

        else:
            LOG.info("Successfully wrote profile: %s", args.output_file)

    return 0


if __name__ == "__main__":
    sys.exit(main())


================================================
FILE: bandit/cli/main.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import fnmatch
import logging
import os
import sys
import textwrap

import bandit
from bandit.core import config as b_config
from bandit.core import constants
from bandit.core import manager as b_manager
from bandit.core import utils

BASE_CONFIG = "bandit.yaml"
LOG = logging.getLogger()


def _init_logger(log_level=logging.INFO, log_format=None):
    """Initialize the logger.

    :param debug: Whether to enable debug mode
    :return: An instantiated logging instance
    """
    LOG.handlers = []

    if not log_format:
        # default log format
        log_format_string = constants.log_format_string
    else:
        log_format_string = log_format

    logging.captureWarnings(True)

    LOG.setLevel(log_level)
    handler = logging.StreamHandler(sys.stderr)
    handler.setFormatter(logging.Formatter(log_format_string))
    LOG.addHandler(handler)
    LOG.debug("logging initialized")


def _get_options_from_ini(ini_path, target):
    """Return a dictionary of config options or None if we can't load any."""
    ini_file = None

    if ini_path:
        ini_file = ini_path
    else:
        bandit_files = []

        for t in target:
            for root, _, filenames in os.walk(t):
                for filename in fnmatch.filter(filenames, ".bandit"):
                    bandit_files.append(os.path.join(root, filename))

        if len(bandit_files) > 1:
            LOG.error(
                "Multiple .bandit files found - scan separately or "
                "choose one with --ini\n\t%s",
                ", ".join(bandit_files),
            )
            sys.exit(2)

        elif len(bandit_files) == 1:
            ini_file = bandit_files[0]
            LOG.info("Found project level .bandit file: %s", bandit_files[0])

    if ini_file:
        return utils.parse_ini_file(ini_file)
    else:
        return None


def _init_extensions():
    from bandit.core import extension_loader as ext_loader

    return ext_loader.MANAGER


def _log_option_source(default_val, arg_val, ini_val, option_name):
    """It's useful to show the source of each option."""
    # When default value is not defined, arg_val and ini_val is deterministic
    if default_val is None:
        if arg_val:
            LOG.info("Using command line arg for %s", option_name)
            return arg_val
        elif ini_val:
            LOG.info("Using ini file for %s", option_name)
            return ini_val
        else:
            return None
    # No value passed to command line and default value is used
    elif default_val == arg_val:
        return ini_val if ini_val else arg_val
    # Certainly a value is passed to command line
    else:
        return arg_val


def _running_under_virtualenv():
    if hasattr(sys, "real_prefix"):
        return True
    elif sys.prefix != getattr(sys, "base_prefix", sys.prefix):
        return True


def _get_profile(config, profile_name, config_path):
    profile = {}
    if profile_name:
        profiles = config.get_option("profiles") or {}
        profile = profiles.get(profile_name)
        if profile is None:
            raise utils.ProfileNotFound(config_path, profile_name)
        LOG.debug("read in legacy profile '%s': %s", profile_name, profile)
    else:
        profile["include"] = set(config.get_option("tests") or [])
        profile["exclude"] = set(config.get_option("skips") or [])
    return profile


def _log_info(args, profile):
    inc = ",".join([t for t in profile["include"]]) or "None"
    exc = ",".join([t for t in profile["exclude"]]) or "None"
    LOG.info("profile include tests: %s", inc)
    LOG.info("profile exclude tests: %s", exc)
    LOG.info("cli include tests: %s", args.tests)
    LOG.info("cli exclude tests: %s", args.skips)


def main():
    """Bandit CLI."""
    # bring our logging stuff up as early as possible
    debug = (
        logging.DEBUG
        if "-d" in sys.argv or "--debug" in sys.argv
        else logging.INFO
    )
    _init_logger(debug)
    extension_mgr = _init_extensions()

    baseline_formatters = [
        f.name
        for f in filter(
            lambda x: hasattr(x.plugin, "_accepts_baseline"),
            extension_mgr.formatters,
        )
    ]

    # now do normal startup
    parser = argparse.ArgumentParser(
        description="Bandit - a Python source code security analyzer",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    if sys.version_info >= (3, 14):
        parser.suggest_on_error = True
        parser.color = False

    parser.add_argument(
        "targets",
        metavar="targets",
        type=str,
        nargs="*",
        help="source file(s) or directory(s) to be tested",
    )
    parser.add_argument(
        "-r",
        "--recursive",
        dest="recursive",
        action="store_true",
        help="find and process files in subdirectories",
    )
    parser.add_argument(
        "-a",
        "--aggregate",
        dest="agg_type",
        action="store",
        default="file",
        type=str,
        choices=["file", "vuln"],
        help="aggregate output by vulnerability (default) or by filename",
    )
    parser.add_argument(
        "-n",
        "--number",
        dest="context_lines",
        action="store",
        default=3,
        type=int,
        help="maximum number of code lines to output for each issue",
    )
    parser.add_argument(
        "-c",
        "--configfile",
        dest="config_file",
        action="store",
        default=None,
        type=str,
        help="optional config file to use for selecting plugins and "
        "overriding defaults",
    )
    parser.add_argument(
        "-p",
        "--profile",
        dest="profile",
        action="store",
        default=None,
        type=str,
        help="profile to use (defaults to executing all tests)",
    )
    parser.add_argument(
        "-t",
        "--tests",
        dest="tests",
        action="store",
        default=None,
        type=str,
        help="comma-separated list of test IDs to run",
    )
    parser.add_argument(
        "-s",
        "--skip",
        dest="skips",
        action="store",
        default=None,
        type=str,
        help="comma-separated list of test IDs to skip",
    )
    severity_group = parser.add_mutually_exclusive_group(required=False)
    severity_group.add_argument(
        "-l",
        "--level",
        dest="severity",
        action="count",
        default=1,
        help="report only issues of a given severity level or "
        "higher (-l for LOW, -ll for MEDIUM, -lll for HIGH)",
    )
    severity_group.add_argument(
        "--severity-level",
        dest="severity_string",
        action="store",
        help="report only issues of a given severity level or higher."
        ' "all" and "low" are likely to produce the same results, but it'
        " is possible for rules to be undefined which will"
        ' not be listed in "low".',
        choices=["all", "low", "medium", "high"],
    )
    confidence_group = parser.add_mutually_exclusive_group(required=False)
    confidence_group.add_argument(
        "-i",
        "--confidence",
        dest="confidence",
        action="count",
        default=1,
        help="report only issues of a given confidence level or "
        "higher (-i for LOW, -ii for MEDIUM, -iii for HIGH)",
    )
    confidence_group.add_argument(
        "--confidence-level",
        dest="confidence_string",
        action="store",
        help="report only issues of a given confidence level or higher."
        ' "all" and "low" are likely to produce the same results, but it'
        " is possible for rules to be undefined which will"
        ' not be listed in "low".',
        choices=["all", "low", "medium", "high"],
    )
    output_format = (
        "screen"
        if (
            sys.stdout.isatty()
            and os.getenv("NO_COLOR") is None
            and os.getenv("TERM") != "dumb"
        )
        else "txt"
    )
    parser.add_argument(
        "-f",
        "--format",
        dest="output_format",
        action="store",
        default=output_format,
        help="specify output format",
        choices=sorted(extension_mgr.formatter_names),
    )
    parser.add_argument(
        "--msg-template",
        action="store",
        default=None,
        help="specify output message template"
        " (only usable with --format custom),"
        " see CUSTOM FORMAT section"
        " for list of available values",
    )
    parser.add_argument(
        "-o",
        "--output",
        dest="output_file",
        action="store",
        nargs="?",
        type=argparse.FileType("w", encoding="utf-8"),
        default=sys.stdout,
        help="write report to filename",
    )
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument(
        "-v",
        "--verbose",
        dest="verbose",
        action="store_true",
        help="output extra information like excluded and included files",
    )
    parser.add_argument(
        "-d",
        "--debug",
        dest="debug",
        action="store_true",
        help="turn on debug mode",
    )
    group.add_argument(
        "-q",
        "--quiet",
        "--silent",
        dest="quiet",
        action="store_true",
        help="only show output in the case of an error",
    )
    parser.add_argument(
        "--ignore-nosec",
        dest="ignore_nosec",
        action="store_true",
        help="do not skip lines with # nosec comments",
    )
    parser.add_argument(
        "-x",
        "--exclude",
        dest="excluded_paths",
        action="store",
        default=",".join(constants.EXCLUDE),
        help="comma-separated list of paths (glob patterns "
        "supported) to exclude from scan "
        "(note that these are in addition to the excluded "
        "paths provided in the config file) (default: "
        + ",".join(constants.EXCLUDE)
        + ")",
    )
    parser.add_argument(
        "-b",
        "--baseline",
        dest="baseline",
        action="store",
        default=None,
        help="path of a baseline report to compare against "
        "(only JSON-formatted files are accepted)",
    )
    parser.add_argument(
        "--ini",
        dest="ini_path",
        action="store",
        default=None,
        help="path to a .bandit file that supplies command line arguments",
    )
    parser.add_argument(
        "--exit-zero",
        action="store_true",
        dest="exit_zero",
        default=False,
        help="exit with 0, " "even with results found",
    )
    python_ver = sys.version.replace("\n", "")
    parser.add_argument(
        "--version",
        action="version",
        version=f"%(prog)s {bandit.__version__}\n"
        f"  python version = {python_ver}",
    )

    parser.set_defaults(debug=False)
    parser.set_defaults(verbose=False)
    parser.set_defaults(quiet=False)
    parser.set_defaults(ignore_nosec=False)

    plugin_info = [
        f"{a[0]}\t{a[1].name}" for a in extension_mgr.plugins_by_id.items()
    ]
    blacklist_info = []
    for a in extension_mgr.blacklist.items():
        for b in a[1]:
            blacklist_info.append(f"{b['id']}\t{b['name']}")

    plugin_list = "\n\t".join(sorted(set(plugin_info + blacklist_info)))
    dedent_text = textwrap.dedent(
        """
    CUSTOM FORMATTING
    -----------------

    Available tags:

        {abspath}, {relpath}, {line}, {col}, {test_id},
        {severity}, {msg}, {confidence}, {range}

    Example usage:

        Default template:
        bandit -r examples/ --format custom --msg-template \\
        "{abspath}:{line}: {test_id}[bandit]: {severity}: {msg}"

        Provides same output as:
        bandit -r examples/ --format custom

        Tags can also be formatted in python string.format() style:
        bandit -r examples/ --format custom --msg-template \\
        "{relpath:20.20s}: {line:03}: {test_id:^8}: DEFECT: {msg:>20}"

        See python documentation for more information about formatting style:
        https://docs.python.org/3/library/string.html

    The following tests were discovered and loaded:
    -----------------------------------------------
    """
    )
    parser.epilog = dedent_text + f"\t{plugin_list}"

    # setup work - parse arguments, and initialize BanditManager
    args = parser.parse_args()
    # Check if `--msg-template` is not present without custom formatter
    if args.output_format != "custom" and args.msg_template is not None:
        parser.error("--msg-template can only be used with --format=custom")

    # Check if confidence or severity level have been specified with strings
    if args.severity_string is not None:
        if args.severity_string == "all":
            args.severity = 1
        elif args.severity_string == "low":
            args.severity = 2
        elif args.severity_string == "medium":
            args.severity = 3
        elif args.severity_string == "high":
            args.severity = 4
        # Other strings will be blocked by argparse

    if args.confidence_string is not None:
        if args.confidence_string == "all":
            args.confidence = 1
        elif args.confidence_string == "low":
            args.confidence = 2
        elif args.confidence_string == "medium":
            args.confidence = 3
        elif args.confidence_string == "high":
            args.confidence = 4
        # Other strings will be blocked by argparse

    # Handle .bandit files in projects to pass cmdline args from file
    ini_options = _get_options_from_ini(args.ini_path, args.targets)
    if ini_options:
        # prefer command line, then ini file
        args.config_file = _log_option_source(
            parser.get_default("configfile"),
            args.config_file,
            ini_options.get("configfile"),
            "config file",
        )

        args.excluded_paths = _log_option_source(
            parser.get_default("excluded_paths"),
            args.excluded_paths,
            ini_options.get("exclude"),
            "excluded paths",
        )

        args.skips = _log_option_source(
            parser.get_default("skips"),
            args.skips,
            ini_options.get("skips"),
            "skipped tests",
        )

        args.tests = _log_option_source(
            parser.get_default("tests"),
            args.tests,
            ini_options.get("tests"),
            "selected tests",
        )

        ini_targets = ini_options.get("targets")
        if ini_targets:
            ini_targets = ini_targets.split(",")

        args.targets = _log_option_source(
            parser.get_default("targets"),
            args.targets,
            ini_targets,
            "selected targets",
        )

        # TODO(tmcpeak): any other useful options to pass from .bandit?

        args.recursive = _log_option_source(
            parser.get_default("recursive"),
            args.recursive,
            ini_options.get("recursive"),
            "recursive scan",
        )

        args.agg_type = _log_option_source(
            parser.get_default("agg_type"),
            args.agg_type,
            ini_options.get("aggregate"),
            "aggregate output type",
        )

        args.context_lines = _log_option_source(
            parser.get_default("context_lines"),
            args.context_lines,
            int(ini_options.get("number") or 0) or None,
            "max code lines output for issue",
        )

        args.profile = _log_option_source(
            parser.get_default("profile"),
            args.profile,
            ini_options.get("profile"),
            "profile",
        )

        args.severity = _log_option_source(
            parser.get_default("severity"),
            args.severity,
            ini_options.get("level"),
            "severity level",
        )

        args.confidence = _log_option_source(
            parser.get_default("confidence"),
            args.confidence,
            ini_options.get("confidence"),
            "confidence level",
        )

        args.output_format = _log_option_source(
            parser.get_default("output_format"),
            args.output_format,
            ini_options.get("format"),
            "output format",
        )

        args.msg_template = _log_option_source(
            parser.get_default("msg_template"),
            args.msg_template,
            ini_options.get("msg-template"),
            "output message template",
        )

        args.output_file = _log_option_source(
            parser.get_default("output_file"),
            args.output_file,
            ini_options.get("output"),
            "output file",
        )

        args.verbose = _log_option_source(
            parser.get_default("verbose"),
            args.verbose,
            ini_options.get("verbose"),
            "output extra information",
        )

        args.debug = _log_option_source(
            parser.get_default("debug"),
            args.debug,
            ini_options.get("debug"),
            "debug mode",
        )

        args.quiet = _log_option_source(
            parser.get_default("quiet"),
            args.quiet,
            ini_options.get("quiet"),
            "silent mode",
        )

        args.ignore_nosec = _log_option_source(
            parser.get_default("ignore_nosec"),
            args.ignore_nosec,
            ini_options.get("ignore-nosec"),
            "do not skip lines with # nosec",
        )

        args.baseline = _log_option_source(
            parser.get_default("baseline"),
            args.baseline,
            ini_options.get("baseline"),
            "path of a baseline report",
        )

    try:
        b_conf = b_config.BanditConfig(config_file=args.config_file)
    except utils.ConfigError as e:
        LOG.error(e)
        sys.exit(2)

    if not args.targets:
        parser.print_usage()
        sys.exit(2)

    # if the log format string was set in the options, reinitialize
    if b_conf.get_option("log_format"):
        log_format = b_conf.get_option("log_format")
        _init_logger(log_level=logging.DEBUG, log_format=log_format)

    if args.quiet:
        _init_logger(log_level=logging.WARN)

    try:
        profile = _get_profile(b_conf, args.profile, args.config_file)
        _log_info(args, profile)

        profile["include"].update(args.tests.split(",") if args.tests else [])
        profile["exclude"].update(args.skips.split(",") if args.skips else [])
        extension_mgr.validate_profile(profile)

    except (utils.ProfileNotFound, ValueError) as e:
        LOG.error(e)
        sys.exit(2)

    b_mgr = b_manager.BanditManager(
        b_conf,
        args.agg_type,
        args.debug,
        profile=profile,
        verbose=args.verbose,
        quiet=args.quiet,
        ignore_nosec=args.ignore_nosec,
    )

    if args.baseline is not None:
        try:
            with open(args.baseline) as bl:
                data = bl.read()
                b_mgr.populate_baseline(data)
        except OSError:
            LOG.warning("Could not open baseline report: %s", args.baseline)
            sys.exit(2)

        if args.output_format not in baseline_formatters:
            LOG.warning(
                "Baseline must be used with one of the following "
                "formats: " + str(baseline_formatters)
            )
            sys.exit(2)

    if args.output_format != "json":
        if args.config_file:
            LOG.info("using config: %s", args.config_file)

        LOG.info(
            "running on Python %d.%d.%d",
            sys.version_info.major,
            sys.version_info.minor,
            sys.version_info.micro,
        )

    # initiate file discovery step within Bandit Manager
    b_mgr.discover_files(args.targets, args.recursive, args.excluded_paths)

    if not b_mgr.b_ts.tests:
        LOG.error("No tests would be run, please check the profile.")
        sys.exit(2)

    # initiate execution of tests within Bandit Manager
    b_mgr.run_tests()
    LOG.debug(b_mgr.b_ma)
    LOG.debug(b_mgr.metrics)

    # trigger output of results by Bandit Manager
    sev_level = constants.RANKING[args.severity - 1]
    conf_level = constants.RANKING[args.confidence - 1]
    b_mgr.output_results(
        args.context_lines,
        sev_level,
        conf_level,
        args.output_file,
        args.output_format,
        args.msg_template,
    )

    if (
        b_mgr.results_count(sev_filter=sev_level, conf_filter=conf_level) > 0
        and not args.exit_zero
    ):
        sys.exit(1)
    else:
        sys.exit(0)


if __name__ == "__main__":
    main()


================================================
FILE: bandit/core/__init__.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
from bandit.core import config  # noqa
from bandit.core import context  # noqa
from bandit.core import manager  # noqa
from bandit.core import meta_ast  # noqa
from bandit.core import node_visitor  # noqa
from bandit.core import test_set  # noqa
from bandit.core import tester  # noqa
from bandit.core import utils  # noqa
from bandit.core.constants import *  # noqa
from bandit.core.issue import *  # noqa
from bandit.core.test_properties import *  # noqa


================================================
FILE: bandit/core/blacklisting.py
================================================
#
# Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import ast

from bandit.core import issue


def report_issue(check, name):
    return issue.Issue(
        severity=check.get("level", "MEDIUM"),
        confidence="HIGH",
        cwe=check.get("cwe", issue.Cwe.NOTSET),
        text=check["message"].replace("{name}", name),
        ident=name,
        test_id=check.get("id", "LEGACY"),
    )


def blacklist(context, config):
    """Generic blacklist test, B001.

    This generic blacklist test will be called for any encountered node with
    defined blacklist data available. This data is loaded via plugins using
    the 'bandit.blacklists' entry point. Please see the documentation for more
    details. Each blacklist datum has a unique bandit ID that may be used for
    filtering purposes, or alternatively all blacklisting can be filtered using
    the id of this built in test, 'B001'.
    """
    blacklists = config
    node_type = context.node.__class__.__name__

    if node_type == "Call":
        func = context.node.func
        if isinstance(func, ast.Name) and func.id == "__import__":
            if len(context.node.args):
                if isinstance(
                    context.node.args[0], ast.Constant
                ) and isinstance(context.node.args[0].value, str):
                    name = context.node.args[0].value
                else:
                    # TODO(??): import through a variable, need symbol tab
                    name = "UNKNOWN"
            else:
                name = ""  # handle '__import__()'
        else:
            name = context.call_function_name_qual
            # In the case the Call is an importlib.import, treat the first
            # argument name as an actual import module name.
            # Will produce None if argument is not a literal or identifier
            if name in ["importlib.import_module", "importlib.__import__"]:
                if context.call_args_count > 0:
                    name = context.call_args[0]
                else:
                    name = context.call_keywords["name"]
        for check in blacklists[node_type]:
            for qn in check["qualnames"]:
                if name is not None and name == qn:
                    return report_issue(check, name)

    if node_type.startswith("Import"):
        prefix = ""
        if node_type == "ImportFrom":
            if context.node.module is not None:
                prefix = context.node.module + "."

        for check in blacklists[node_type]:
            for name in context.node.names:
                for qn in check["qualnames"]:
                    if (prefix + name.name).startswith(qn):
                        return report_issue(check, name.name)


================================================
FILE: bandit/core/config.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import logging
import sys

import yaml

if sys.version_info >= (3, 11):
    import tomllib
else:
    try:
        import tomli as tomllib
    except ImportError:
        tomllib = None

from bandit.core import constants
from bandit.core import extension_loader
from bandit.core import utils

LOG = logging.getLogger(__name__)


class BanditConfig:
    def __init__(self, config_file=None):
        """Attempt to initialize a config dictionary from a yaml file.

        Error out if loading the yaml file fails for any reason.
        :param config_file: The Bandit yaml config file

        :raises bandit.utils.ConfigError: If the config is invalid or
            unreadable.
        """
        self.config_file = config_file
        self._config = {}

        if config_file:
            try:
                f = open(config_file, "rb")
            except OSError:
                raise utils.ConfigError(
                    "Could not read config file.", config_file
                )

            if config_file.endswith(".toml"):
                if tomllib is None:
                    raise utils.ConfigError(
                        "toml parser not available, reinstall with toml extra",
                        config_file,
                    )

                try:
                    with f:
                        self._config = (
                            tomllib.load(f).get("tool", {}).get("bandit", {})
                        )
                except tomllib.TOMLDecodeError as err:
                    LOG.error(err)
                    raise utils.ConfigError("Error parsing file.", config_file)
            else:
                try:
                    with f:
                        self._config = yaml.safe_load(f)
                except yaml.YAMLError as err:
                    LOG.error(err)
                    raise utils.ConfigError("Error parsing file.", config_file)

            self.validate(config_file)

            # valid config must be a dict
            if not isinstance(self._config, dict):
                raise utils.ConfigError("Error parsing file.", config_file)

            self.convert_legacy_config()

        else:
            # use sane defaults
            self._config["plugin_name_pattern"] = "*.py"
            self._config["include"] = ["*.py", "*.pyw"]

        self._init_settings()

    def get_option(self, option_string):
        """Returns the option from the config specified by the option_string.

        '.' can be used to denote levels, for example to retrieve the options
        from the 'a' profile you can use 'profiles.a'
        :param option_string: The string specifying the option to retrieve
        :return: The object specified by the option_string, or None if it can't
        be found.
        """
        option_levels = option_string.split(".")
        cur_item = self._config
        for level in option_levels:
            if cur_item and (level in cur_item):
                cur_item = cur_item[level]
            else:
                return None

        return cur_item

    def get_setting(self, setting_name):
        if setting_name in self._settings:
            return self._settings[setting_name]
        else:
            return None

    @property
    def config(self):
        """Property to return the config dictionary

        :return: Config dictionary
        """
        return self._config

    def _init_settings(self):
        """This function calls a set of other functions (one per setting)

        This function calls a set of other functions (one per setting) to build
        out the _settings dictionary.  Each other function will set values from
        the config (if set), otherwise use defaults (from constants if
        possible).
        :return: -
        """
        self._settings = {}
        self._init_plugin_name_pattern()

    def _init_plugin_name_pattern(self):
        """Sets settings['plugin_name_pattern'] from default or config file."""
        plugin_name_pattern = constants.plugin_name_pattern
        if self.get_option("plugin_name_pattern"):
            plugin_name_pattern = self.get_option("plugin_name_pattern")
        self._settings["plugin_name_pattern"] = plugin_name_pattern

    def convert_legacy_config(self):
        updated_profiles = self.convert_names_to_ids()
        bad_calls, bad_imports = self.convert_legacy_blacklist_data()

        if updated_profiles:
            self.convert_legacy_blacklist_tests(
                updated_profiles, bad_calls, bad_imports
            )
            self._config["profiles"] = updated_profiles

    def convert_names_to_ids(self):
        """Convert test names to IDs, unknown names are left unchanged."""
        extman = extension_loader.MANAGER

        updated_profiles = {}
        for name, profile in (self.get_option("profiles") or {}).items():
            # NOTE(tkelsey): can't use default of get() because value is
            # sometimes explicitly 'None', for example when the list is given
            # in yaml but not populated with any values.
            include = {
                (extman.get_test_id(i) or i)
                for i in (profile.get("include") or [])
            }
            exclude = {
                (extman.get_test_id(i) or i)
                for i in (profile.get("exclude") or [])
            }
            updated_profiles[name] = {"include": include, "exclude": exclude}
        return updated_profiles

    def convert_legacy_blacklist_data(self):
        """Detect legacy blacklist data and convert it to new format."""
        bad_calls_list = []
        bad_imports_list = []

        bad_calls = self.get_option("blacklist_calls") or {}
        bad_calls = bad_calls.get("bad_name_sets", {})
        for item in bad_calls:
            for key, val in item.items():
                val["name"] = key
                val["message"] = val["message"].replace("{func}", "{name}")
                bad_calls_list.append(val)

        bad_imports = self.get_option("blacklist_imports") or {}
        bad_imports = bad_imports.get("bad_import_sets", {})
        for item in bad_imports:
            for key, val in item.items():
                val["name"] = key
                val["message"] = val["message"].replace("{module}", "{name}")
                val["qualnames"] = val["imports"]
                del val["imports"]
                bad_imports_list.append(val)

        if bad_imports_list or bad_calls_list:
            LOG.warning(
                "Legacy blacklist data found in config, overriding "
                "data plugins"
            )
        return bad_calls_list, bad_imports_list

    @staticmethod
    def convert_legacy_blacklist_tests(profiles, bad_imports, bad_calls):
        """Detect old blacklist tests, convert to use new builtin."""

        def _clean_set(name, data):
            if name in data:
                data.remove(name)
                data.add("B001")

        for name, profile in profiles.items():
            blacklist = {}
            include = profile["include"]
            exclude = profile["exclude"]

            name = "blacklist_calls"
            if name in include and name not in exclude:
                blacklist.setdefault("Call", []).extend(bad_calls)

            _clean_set(name, include)
            _clean_set(name, exclude)

            name = "blacklist_imports"
            if name in include and name not in exclude:
                blacklist.setdefault("Import", []).extend(bad_imports)
                blacklist.setdefault("ImportFrom", []).extend(bad_imports)
                blacklist.setdefault("Call", []).extend(bad_imports)

            _clean_set(name, include)
            _clean_set(name, exclude)
            _clean_set("blacklist_import_func", include)
            _clean_set("blacklist_import_func", exclude)

            # This can happen with a legacy config that includes
            # blacklist_calls but exclude blacklist_imports for example
            if "B001" in include and "B001" in exclude:
                exclude.remove("B001")

            profile["blacklist"] = blacklist

    def validate(self, path):
        """Validate the config data."""
        legacy = False
        message = (
            "Config file has an include or exclude reference "
            "to legacy test '{0}' but no configuration data for "
            "it. Configuration data is required for this test. "
            "Please consider switching to the new config file "
            "format, the tool 'bandit-config-generator' can help "
            "you with this."
        )

        def _test(key, block, exclude, include):
            if key in exclude or key in include:
                if self._config.get(block) is None:
                    raise utils.ConfigError(message.format(key), path)

        if "profiles" in self._config:
            legacy = True
            for profile in self._config["profiles"].values():
                inc = profile.get("include") or set()
                exc = profile.get("exclude") or set()

                _test("blacklist_imports", "blacklist_imports", inc, exc)
                _test("blacklist_import_func", "blacklist_imports", inc, exc)
                _test("blacklist_calls", "blacklist_calls", inc, exc)

        # show deprecation message
        if legacy:
            LOG.warning(
                "Config file '%s' contains deprecated legacy config "
                "data. Please consider upgrading to the new config "
                "format. The tool 'bandit-config-generator' can help "
                "you with this. Support for legacy configs will be "
                "removed in a future bandit version.",
                path,
            )


================================================
FILE: bandit/core/constants.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
# default plugin name pattern
plugin_name_pattern = "*.py"

RANKING = ["UNDEFINED", "LOW", "MEDIUM", "HIGH"]
RANKING_VALUES = {"UNDEFINED": 1, "LOW": 3, "MEDIUM": 5, "HIGH": 10}
CRITERIA = [("SEVERITY", "UNDEFINED"), ("CONFIDENCE", "UNDEFINED")]

# add each ranking to globals, to allow direct access in module name space
for rank in RANKING:
    globals()[rank] = rank

CONFIDENCE_DEFAULT = "UNDEFINED"

# A list of values Python considers to be False.
# These can be useful in tests to check if a value is True or False.
# We don't handle the case of user-defined classes being false.
# These are only useful when we have a constant in code. If we
# have a variable we cannot determine if False.
# See https://docs.python.org/3/library/stdtypes.html#truth-value-testing
FALSE_VALUES = [None, False, "False", 0, 0.0, 0j, "", (), [], {}]

# override with "log_format" option in config file
log_format_string = "[%(module)s]\t%(levelname)s\t%(message)s"

# Directories to exclude by default
EXCLUDE = (
    ".svn",
    "CVS",
    ".bzr",
    ".hg",
    ".git",
    "__pycache__",
    ".tox",
    ".eggs",
    "*.egg",
)


================================================
FILE: bandit/core/context.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import ast

from bandit.core import utils


class Context:
    def __init__(self, context_object=None):
        """Initialize the class with a context, empty dict otherwise

        :param context_object: The context object to create class from
        :return: -
        """
        if context_object is not None:
            self._context = context_object
        else:
            self._context = dict()

    def __repr__(self):
        """Generate representation of object for printing / interactive use

        Most likely only interested in non-default properties, so we return
        the string version of _context.

        Example string returned:
        <Context {'node': <_ast.Call object at 0x110252510>, 'function': None,
        'name': 'socket', 'imports': set(['socket']), 'module': None,
        'filename': 'examples/binding.py',
        'call': <_ast.Call object at 0x110252510>, 'lineno': 3,
        'import_aliases': {}, 'qualname': 'socket.socket'}>

        :return: A string representation of the object
        """
        return f"<Context {self._context}>"

    @property
    def call_args(self):
        """Get a list of function args

        :return: A list of function args
        """
        args = []
        if "call" in self._context and hasattr(self._context["call"], "args"):
            for arg in self._context["call"].args:
                if hasattr(arg, "attr"):
                    args.append(arg.attr)
                else:
                    args.append(self._get_literal_value(arg))
        return args

    @property
    def call_args_count(self):
        """Get the number of args a function call has

        :return: The number of args a function call has or None
        """
        if "call" in self._context and hasattr(self._context["call"], "args"):
            return len(self._context["call"].args)
        else:
            return None

    @property
    def call_function_name(self):
        """Get the name (not FQ) of a function call

        :return: The name (not FQ) of a function call
        """
        return self._context.get("name")

    @property
    def call_function_name_qual(self):
        """Get the FQ name of a function call

        :return: The FQ name of a function call
        """
        return self._context.get("qualname")

    @property
    def call_keywords(self):
        """Get a dictionary of keyword parameters

        :return: A dictionary of keyword parameters for a call as strings
        """
        if "call" in self._context and hasattr(
            self._context["call"], "keywords"
        ):
            return_dict = {}
            for li in self._context["call"].keywords:
                if hasattr(li.value, "attr"):
                    return_dict[li.arg] = li.value.attr
                else:
                    return_dict[li.arg] = self._get_literal_value(li.value)
            return return_dict
        else:
            return None

    @property
    def node(self):
        """Get the raw AST node associated with the context

        :return: The raw AST node associated with the context
        """
        return self._context.get("node")

    @property
    def string_val(self):
        """Get the value of a standalone unicode or string object

        :return: value of a standalone unicode or string object
        """
        return self._context.get("str")

    @property
    def bytes_val(self):
        """Get the value of a standalone bytes object (py3 only)

        :return: value of a standalone bytes object
        """
        return self._context.get("bytes")

    @property
    def string_val_as_escaped_bytes(self):
        """Get escaped value of the object.

        Turn the value of a string or bytes object into byte sequence with
        unknown, control, and \\ characters escaped.

        This function should be used when looking for a known sequence in a
        potentially badly encoded string in the code.

        :return: sequence of printable ascii bytes representing original string
        """
        val = self.string_val
        if val is not None:
            # it's any of str or unicode in py2, or str in py3
            return val.encode("unicode_escape")

        val = self.bytes_val
        if val is not None:
            return utils.escaped_bytes_representation(val)

        return None

    @property
    def statement(self):
        """Get the raw AST for the current statement

        :return: The raw AST for the current statement
        """
        return self._context.get("statement")

    @property
    def function_def_defaults_qual(self):
        """Get a list of fully qualified default values in a function def

        :return: List of defaults
        """
        defaults = []
        if (
            "node" in self._context
            and hasattr(self._context["node"], "args")
            and hasattr(self._context["node"].args, "defaults")
        ):
            for default in self._context["node"].args.defaults:
                defaults.append(
                    utils.get_qual_attr(
                        default, self._context["import_aliases"]
                    )
                )
        return defaults

    def _get_literal_value(self, literal):
        """Utility function to turn AST literals into native Python types

        :param literal: The AST literal to convert
        :return: The value of the AST literal
        """
        if isinstance(literal, ast.Constant):
            if isinstance(literal.value, bool):
                literal_value = str(literal.value)
            elif literal.value is None:
                literal_value = str(literal.value)
            else:
                literal_value = literal.value

        elif isinstance(literal, ast.List):
            return_list = list()
            for li in literal.elts:
                return_list.append(self._get_literal_value(li))
            literal_value = return_list

        elif isinstance(literal, ast.Tuple):
            return_tuple = tuple()
            for ti in literal.elts:
                return_tuple += (self._get_literal_value(ti),)
            literal_value = return_tuple

        elif isinstance(literal, ast.Set):
            return_set = set()
            for si in literal.elts:
                return_set.add(self._get_literal_value(si))
            literal_value = return_set

        elif isinstance(literal, ast.Dict):
            literal_value = dict(zip(literal.keys, literal.values))

        elif isinstance(literal, ast.Name):
            literal_value = literal.id

        else:
            literal_value = None

        return literal_value

    def get_call_arg_value(self, argument_name):
        """Gets the value of a named argument in a function call.

        :return: named argument value
        """
        kwd_values = self.call_keywords
        if kwd_values is not None and argument_name in kwd_values:
            return kwd_values[argument_name]

    def check_call_arg_value(self, argument_name, argument_values=None):
        """Checks for a value of a named argument in a function call.

        Returns none if the specified argument is not found.
        :param argument_name: A string - name of the argument to look for
        :param argument_values: the value, or list of values to test against
        :return: Boolean True if argument found and matched, False if
        found and not matched, None if argument not found at all
        """
        arg_value = self.get_call_arg_value(argument_name)
        if arg_value is not None:
            if not isinstance(argument_values, list):
                # if passed a single value, or a tuple, convert to a list
                argument_values = list((argument_values,))
            for val in argument_values:
                if arg_value == val:
                    return True
            return False
        else:
            # argument name not found, return None to allow testing for this
            # eventuality
            return None

    def get_lineno_for_call_arg(self, argument_name):
        """Get the line number for a specific named argument

        In case the call is split over multiple lines, get the correct one for
        the argument.
        :param argument_name: A string - name of the argument to look for
        :return: Integer - the line number of the found argument, or -1
        """
        if hasattr(self.node, "keywords"):
            for key in self.node.keywords:
                if key.arg == argument_name:
                    return key.value.lineno

    def get_call_arg_at_position(self, position_num):
        """Returns positional argument at the specified position (if it exists)

        :param position_num: The index of the argument to return the value for
        :return: Value of the argument at the specified position if it exists
        """
        max_args = self.call_args_count
        if max_args and position_num < max_args:
            arg = self._context["call"].args[position_num]
            return getattr(arg, "attr", None) or self._get_literal_value(arg)
        else:
            return None

    def is_module_being_imported(self, module):
        """Check for the specified module is currently being imported

        :param module: The module name to look for
        :return: True if the module is found, False otherwise
        """
        return self._context.get("module") == module

    def is_module_imported_exact(self, module):
        """Check if a specified module has been imported; only exact matches.

        :param module: The module name to look for
        :return: True if the module is found, False otherwise
        """
        return module in self._context.get("imports", [])

    def is_module_imported_like(self, module):
        """Check if a specified module has been imported

        Check if a specified module has been imported; specified module exists
        as part of any import statement.
        :param module: The module name to look for
        :return: True if the module is found, False otherwise
        """
        if "imports" in self._context:
            for imp in self._context["imports"]:
                if module in imp:
                    return True
        return False

    @property
    def filename(self):
        return self._context.get("filename")

    @property
    def file_data(self):
        return self._context.get("file_data")

    @property
    def import_aliases(self):
        return self._context.get("import_aliases")


================================================
FILE: bandit/core/docs_utils.py
================================================
#
# Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import bandit


def get_url(bid):
    # where our docs are hosted
    base_url = f"https://bandit.readthedocs.io/en/{bandit.__version__}/"

    # NOTE(tkelsey): for some reason this import can't be found when stevedore
    # loads up the formatter plugin that imports this file. It is available
    # later though.
    from bandit.core import extension_loader

    info = extension_loader.MANAGER.plugins_by_id.get(bid)
    if info is not None:
        return f"{base_url}plugins/{bid.lower()}_{info.plugin.__name__}.html"

    info = extension_loader.MANAGER.blacklist_by_id.get(bid)
    if info is not None:
        template = "blacklists/blacklist_{kind}.html#{id}-{name}"
        info["name"] = info["name"].replace("_", "-")

        if info["id"].startswith("B3"):  # B3XX
            # Some of the links are combined, so we have exception cases
            if info["id"] in ["B304", "B305"]:
                info = info.copy()
                info["id"] = "b304-b305"
                info["name"] = "ciphers-and-modes"
            elif info["id"] in [
                "B313",
                "B314",
                "B315",
                "B316",
                "B317",
                "B318",
                "B319",
                "B320",
            ]:
                info = info.copy()
                info["id"] = "b313-b320"
            ext = template.format(
                kind="calls", id=info["id"], name=info["name"]
            )
        else:
            ext = template.format(
                kind="imports", id=info["id"], name=info["name"]
            )

        return base_url + ext.lower()

    return base_url  # no idea, give the docs main page


================================================
FILE: bandit/core/extension_loader.py
================================================
#
# SPDX-License-Identifier: Apache-2.0
import logging
import sys

from stevedore import extension

from bandit.core import utils

LOG = logging.getLogger(__name__)


class Manager:
    # These IDs are for bandit built in tests
    builtin = ["B001"]  # Built in blacklist test

    def __init__(
        self,
        formatters_namespace="bandit.formatters",
        plugins_namespace="bandit.plugins",
        blacklists_namespace="bandit.blacklists",
    ):
        # Cache the extension managers, loaded extensions, and extension names
        self.load_formatters(formatters_namespace)
        self.load_plugins(plugins_namespace)
        self.load_blacklists(blacklists_namespace)

    def load_formatters(self, formatters_namespace):
        self.formatters_mgr = extension.ExtensionManager(
            namespace=formatters_namespace,
            invoke_on_load=False,
            verify_requirements=False,
        )
        self.formatters = list(self.formatters_mgr)
        self.formatter_names = self.formatters_mgr.names()

    def load_plugins(self, plugins_namespace):
        self.plugins_mgr = extension.ExtensionManager(
            namespace=plugins_namespace,
            invoke_on_load=False,
            verify_requirements=False,
        )

        def test_has_id(plugin):
            if not hasattr(plugin.plugin, "_test_id"):
                # logger not setup yet, so using print
                print(
                    f"WARNING: Test '{plugin.name}' has no ID, skipping.",
                    file=sys.stderr,
                )
                return False
            return True

        self.plugins = list(filter(test_has_id, list(self.plugins_mgr)))
        self.plugin_names = [plugin.name for plugin in self.plugins]
        self.plugins_by_id = {p.plugin._test_id: p for p in self.plugins}
        self.plugins_by_name = {p.name: p for p in self.plugins}

    def get_test_id(self, test_name):
        if test_name in self.plugins_by_name:
            return self.plugins_by_name[test_name].plugin._test_id
        if test_name in self.blacklist_by_name:
            return self.blacklist_by_name[test_name]["id"]
        return None

    def load_blacklists(self, blacklist_namespace):
        self.blacklists_mgr = extension.ExtensionManager(
            namespace=blacklist_namespace,
            invoke_on_load=False,
            verify_requirements=False,
        )
        self.blacklist = {}
        blacklist = list(self.blacklists_mgr)
        for item in blacklist:
            for key, val in item.plugin().items():
                utils.check_ast_node(key)
                self.blacklist.setdefault(key, []).extend(val)

        self.blacklist_by_id = {}
        self.blacklist_by_name = {}
        for val in self.blacklist.values():
            for b in val:
                self.blacklist_by_id[b["id"]] = b
                self.blacklist_by_name[b["name"]] = b

    def validate_profile(self, profile):
        """Validate that everything in the configured profiles looks good."""
        for inc in profile["include"]:
            if not self.check_id(inc):
                LOG.warning(f"Unknown test found in profile: {inc}")

        for exc in profile["exclude"]:
            if not self.check_id(exc):
                LOG.warning(f"Unknown test found in profile: {exc}")

        union = set(profile["include"]) & set(profile["exclude"])
        if len(union) > 0:
            raise ValueError(
                f"Non-exclusive include/exclude test sets: {union}"
            )

    def check_id(self, test):
        return (
            test in self.plugins_by_id
            or test in self.blacklist_by_id
            or test in self.builtin
        )


# Using entry-points and pkg_resources *can* be expensive. So let's load these
# once, store them on the object, and have a module global object for
# accessing them. After the first time this module is imported, it should save
# this attribute on the module and not have to reload the entry-points.
MANAGER = Manager()


================================================
FILE: bandit/core/issue.py
================================================
#
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import linecache

from bandit.core import constants


class Cwe:
    NOTSET = 0
    IMPROPER_INPUT_VALIDATION = 20
    PATH_TRAVERSAL = 22
    OS_COMMAND_INJECTION = 78
    XSS = 79
    BASIC_XSS = 80
    SQL_INJECTION = 89
    CODE_INJECTION = 94
    IMPROPER_WILDCARD_NEUTRALIZATION = 155
    HARD_CODED_PASSWORD = 259
    IMPROPER_ACCESS_CONTROL = 284
    IMPROPER_CERT_VALIDATION = 295
    CLEARTEXT_TRANSMISSION = 319
    INADEQUATE_ENCRYPTION_STRENGTH = 326
    BROKEN_CRYPTO = 327
    INSUFFICIENT_RANDOM_VALUES = 330
    INSECURE_TEMP_FILE = 377
    UNCONTROLLED_RESOURCE_CONSUMPTION = 400
    DOWNLOAD_OF_CODE_WITHOUT_INTEGRITY_CHECK = 494
    DESERIALIZATION_OF_UNTRUSTED_DATA = 502
    MULTIPLE_BINDS = 605
    IMPROPER_CHECK_OF_EXCEPT_COND = 703
    INCORRECT_PERMISSION_ASSIGNMENT = 732
    INAPPROPRIATE_ENCODING_FOR_OUTPUT_CONTEXT = 838

    MITRE_URL_PATTERN = "https://cwe.mitre.org/data/definitions/%s.html"

    def __init__(self, id=NOTSET):
        self.id = id

    def link(self):
        if self.id == Cwe.NOTSET:
            return ""

        return Cwe.MITRE_URL_PATTERN % str(self.id)

    def __str__(self):
        if self.id == Cwe.NOTSET:
            return ""

        return "CWE-%i (%s)" % (self.id, self.link())

    def as_dict(self):
        return (
            {"id": self.id, "link": self.link()}
            if self.id != Cwe.NOTSET
            else {}
        )

    def as_jsons(self):
        return str(self.as_dict())

    def from_dict(self, data):
        if "id" in data:
            self.id = int(data["id"])
        else:
            self.id = Cwe.NOTSET

    def __eq__(self, other):
        return self.id == other.id

    def __ne__(self, other):
        return self.id != other.id

    def __hash__(self):
        return id(self)


class Issue:
    def __init__(
        self,
        severity,
        cwe=0,
        confidence=constants.CONFIDENCE_DEFAULT,
        text="",
        ident=None,
        lineno=None,
        test_id="",
        col_offset=-1,
        end_col_offset=0,
    ):
        self.severity = severity
        self.cwe = Cwe(cwe)
        self.confidence = confidence
        if isinstance(text, bytes):
            text = text.decode("utf-8")
        self.text = text
        self.ident = ident
        self.fname = ""
        self.fdata = None
        self.test = ""
        self.test_id = test_id
        self.lineno = lineno
        self.col_offset = col_offset
        self.end_col_offset = end_col_offset
        self.linerange = []

    def __str__(self):
        return (
            "Issue: '%s' from %s:%s: CWE: %s, Severity: %s Confidence: "
            "%s at %s:%i:%i"
        ) % (
            self.text,
            self.test_id,
            (self.ident or self.test),
            str(self.cwe),
            self.severity,
            self.confidence,
            self.fname,
            self.lineno,
            self.col_offset,
        )

    def __eq__(self, other):
        # if the issue text, severity, confidence, and filename match, it's
        # the same issue from our perspective
        match_types = [
            "text",
            "severity",
            "cwe",
            "confidence",
            "fname",
            "test",
            "test_id",
        ]
        return all(
            getattr(self, field) == getattr(other, field)
            for field in match_types
        )

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return id(self)

    def filter(self, severity, confidence):
        """Utility to filter on confidence and severity

        This function determines whether an issue should be included by
        comparing the severity and confidence rating of the issue to minimum
        thresholds specified in 'severity' and 'confidence' respectively.

        Formatters should call manager.filter_results() directly.

        This will return false if either the confidence or severity of the
        issue are lower than the given threshold values.

        :param severity: Severity threshold
        :param confidence: Confidence threshold
        :return: True/False depending on whether issue meets threshold

        """
        rank = constants.RANKING
        return rank.index(self.severity) >= rank.index(
            severity
        ) and rank.index(self.confidence) >= rank.index(confidence)

    def get_code(self, max_lines=3, tabbed=False):
        """Gets lines of code from a file the generated this issue.

        :param max_lines: Max lines of context to return
        :param tabbed: Use tabbing in the output
        :return: strings of code
        """
        lines = []
        max_lines = max(max_lines, 1)
        lmin = max(1, self.lineno - max_lines // 2)
        lmax = lmin + len(self.linerange) + max_lines - 1

        if self.fname == "<stdin>":
            self.fdata.seek(0)
            for line_num in range(1, lmin):
                self.fdata.readline()

        tmplt = "%i\t%s" if tabbed else "%i %s"
        for line in range(lmin, lmax):
            if self.fname == "<stdin>":
                text = self.fdata.readline()
            else:
                text = linecache.getline(self.fname, line)

            if isinstance(text, bytes):
                text = text.decode("utf-8")

            if not len(text):
                break
            lines.append(tmplt % (line, text))
        return "".join(lines)

    def as_dict(self, with_code=True, max_lines=3):
        """Convert the issue to a dict of values for outputting."""
        out = {
            "filename": self.fname,
            "test_name": self.test,
            "test_id": self.test_id,
            "issue_severity": self.severity,
            "issue_cwe": self.cwe.as_dict(),
            "issue_confidence": self.confidence,
            "issue_text": self.text.encode("utf-8").decode("utf-8"),
            "line_number": self.lineno,
            "line_range": self.linerange,
            "col_offset": self.col_offset,
            "end_col_offset": self.end_col_offset,
        }

        if with_code:
            out["code"] = self.get_code(max_lines=max_lines)
        return out

    def from_dict(self, data, with_code=True):
        self.code = data["code"]
        self.fname = data["filename"]
        self.severity = data["issue_severity"]
        self.cwe = cwe_from_dict(data["issue_cwe"])
        self.confidence = data["issue_confidence"]
        self.text = data["issue_text"]
        self.test = data["test_name"]
        self.test_id = data["test_id"]
        self.lineno = data["line_number"]
        self.linerange = data["line_range"]
        self.col_offset = data.get("col_offset", 0)
        self.end_col_offset = data.get("end_col_offset", 0)


def cwe_from_dict(data):
    cwe = Cwe()
    cwe.from_dict(data)
    return cwe


def issue_from_dict(data):
    i = Issue(severity=data["issue_severity"])
    i.from_dict(data)
    return i


================================================
FILE: bandit/core/manager.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import collections
import fnmatch
import io
import json
import logging
import os
import re
import sys
import tokenize
import traceback

from rich import progress

from bandit.core import constants as b_constants
from bandit.core import extension_loader
from bandit.core import issue
from bandit.core import meta_ast as b_meta_ast
from bandit.core import metrics
from bandit.core import node_visitor as b_node_visitor
from bandit.core import test_set as b_test_set

LOG = logging.getLogger(__name__)
NOSEC_COMMENT = re.compile(r"#\s*nosec:?\s*(?P<tests>[^#]+)?#?")
NOSEC_COMMENT_TESTS = re.compile(r"(?:(B\d+|[a-z\d_]+),?)+", re.IGNORECASE)
PROGRESS_THRESHOLD = 50


class BanditManager:
    scope = []

    def __init__(
        self,
        config,
        agg_type,
        debug=False,
        verbose=False,
        quiet=False,
        profile=None,
        ignore_nosec=False,
    ):
        """Get logger, config, AST handler, and result store ready

        :param config: config options object
        :type config: bandit.core.BanditConfig
        :param agg_type: aggregation type
        :param debug: Whether to show debug messages or not
        :param verbose: Whether to show verbose output
        :param quiet: Whether to only show output in the case of an error
        :param profile_name: Optional name of profile to use (from cmd line)
        :param ignore_nosec: Whether to ignore #nosec or not
        :return:
        """
        self.debug = debug
        self.verbose = verbose
        self.quiet = quiet
        if not profile:
            profile = {}
        self.ignore_nosec = ignore_nosec
        self.b_conf = config
        self.files_list = []
        self.excluded_files = []
        self.b_ma = b_meta_ast.BanditMetaAst()
        self.skipped = []
        self.results = []
        self.baseline = []
        self.agg_type = agg_type
        self.metrics = metrics.Metrics()
        self.b_ts = b_test_set.BanditTestSet(config, profile)
        self.scores = []

    def get_skipped(self):
        ret = []
        # "skip" is a tuple of name and reason, decode just the name
        for skip in self.skipped:
            if isinstance(skip[0], bytes):
                ret.append((skip[0].decode("utf-8"), skip[1]))
            else:
                ret.append(skip)
        return ret

    def get_issue_list(
        self, sev_level=b_constants.LOW, conf_level=b_constants.LOW
    ):
        return self.filter_results(sev_level, conf_level)

    def populate_baseline(self, data):
        """Populate a baseline set of issues from a JSON report

        This will populate a list of baseline issues discovered from a previous
        run of bandit. Later this baseline can be used to filter out the result
        set, see filter_results.
        """
        items = []
        try:
            jdata = json.loads(data)
            items = [issue.issue_from_dict(j) for j in jdata["results"]]
        except Exception as e:
            LOG.warning("Failed to load baseline data: %s", e)
        self.baseline = items

    def filter_results(self, sev_filter, conf_filter):
        """Returns a list of results filtered by the baseline

        This works by checking the number of results returned from each file we
        process. If the number of results is different to the number reported
        for the same file in the baseline, then we return all results for the
        file. We can't reliably return just the new results, as line numbers
        will likely have changed.

        :param sev_filter: severity level filter to apply
        :param conf_filter: confidence level filter to apply
        """

        results = [
            i for i in self.results if i.filter(sev_filter, conf_filter)
        ]

        if not self.baseline:
            return results

        unmatched = _compare_baseline_results(self.baseline, results)
        # if it's a baseline we'll return a dictionary of issues and a list of
        # candidate issues
        return _find_candidate_matches(unmatched, results)

    def results_count(
        self, sev_filter=b_constants.LOW, conf_filter=b_constants.LOW
    ):
        """Return the count of results

        :param sev_filter: Severity level to filter lower
        :param conf_filter: Confidence level to filter
        :return: Number of results in the set
        """
        return len(self.get_issue_list(sev_filter, conf_filter))

    def output_results(
        self,
        lines,
        sev_level,
        conf_level,
        output_file,
        output_format,
        template=None,
    ):
        """Outputs results from the result store

        :param lines: How many surrounding lines to show per result
        :param sev_level: Which severity levels to show (LOW, MEDIUM, HIGH)
        :param conf_level: Which confidence levels to show (LOW, MEDIUM, HIGH)
        :param output_file: File to store results
        :param output_format: output format plugin name
        :param template: Output template with non-terminal tags <N>
                         (default:  {abspath}:{line}:
                         {test_id}[bandit]: {severity}: {msg})
        :return: -
        """
        try:
            formatters_mgr = extension_loader.MANAGER.formatters_mgr
            if output_format not in formatters_mgr:
                output_format = (
                    "screen"
                    if (
                        sys.stdout.isatty()
                        and os.getenv("NO_COLOR") is None
                        and os.getenv("TERM") != "dumb"
                    )
                    else "txt"
                )

            formatter = formatters_mgr[output_format]
            report_func = formatter.plugin
            if output_format == "custom":
                report_func(
                    self,
                    fileobj=output_file,
                    sev_level=sev_level,
                    conf_level=conf_level,
                    template=template,
                )
            else:
                report_func(
                    self,
                    fileobj=output_file,
                    sev_level=sev_level,
                    conf_level=conf_level,
                    lines=lines,
                )

        except Exception as e:
            raise RuntimeError(
                f"Unable to output report using "
                f"'{output_format}' formatter: {str(e)}"
            )

    def discover_files(self, targets, recursive=False, excluded_paths=""):
        """Add tests directly and from a directory to the test set

        :param targets: The command line list of files and directories
        :param recursive: True/False - whether to add all files from dirs
        :return:
        """
        # We'll maintain a list of files which are added, and ones which have
        # been explicitly excluded
        files_list = set()
        excluded_files = set()

        excluded_path_globs = self.b_conf.get_option("exclude_dirs") or []
        included_globs = self.b_conf.get_option("include") or ["*.py"]

        # if there are command line provided exclusions add them to the list
        if excluded_paths:
            for path in excluded_paths.split(","):
                if os.path.isdir(path):
                    path = os.path.join(path, "*")

                excluded_path_globs.append(path)

        # build list of files we will analyze
        for fname in targets:
            # if this is a directory and recursive is set, find all files
            if os.path.isdir(fname):
                if recursive:
                    new_files, newly_excluded = _get_files_from_dir(
                        fname,
                        included_globs=included_globs,
                        excluded_path_strings=excluded_path_globs,
                    )
                    files_list.update(new_files)
                    excluded_files.update(newly_excluded)
                else:
                    LOG.warning(
                        "Skipping directory (%s), use -r flag to "
                        "scan contents",
                        fname,
                    )

            else:
                # if the user explicitly mentions a file on command line,
                # we'll scan it, regardless of whether it's in the included
                # file types list
                if _is_file_included(
                    fname,
                    included_globs,
                    excluded_path_globs,
                    enforce_glob=False,
                ):
                    if fname != "-":
                        fname = os.path.join(".", fname)
                    files_list.add(fname)
                else:
                    excluded_files.add(fname)

        self.files_list = sorted(files_list)
        self.excluded_files = sorted(excluded_files)

    def run_tests(self):
        """Runs through all files in the scope

        :return: -
        """
        # if we have problems with a file, we'll remove it from the files_list
        # and add it to the skipped list instead
        new_files_list = list(self.files_list)
        if (
            len(self.files_list) > PROGRESS_THRESHOLD
            and LOG.getEffectiveLevel() <= logging.INFO
        ):
            files = progress.track(self.files_list)
        else:
            files = self.files_list

        for count, fname in enumerate(files):
            LOG.debug("working on file : %s", fname)

            try:
                if fname == "-":
                    open_fd = os.fdopen(sys.stdin.fileno(), "rb", 0)
                    fdata = io.BytesIO(open_fd.read())
                    new_files_list = [
                        "<stdin>" if x == "-" else x for x in new_files_list
                    ]
                    self._parse_file("<stdin>", fdata, new_files_list)
                else:
                    with open(fname, "rb") as fdata:
                        self._parse_file(fname, fdata, new_files_list)
            except OSError as e:
                self.skipped.append((fname, e.strerror))
                new_files_list.remove(fname)

        # reflect any files which may have been skipped
        self.files_list = new_files_list

        # do final aggregation of metrics
        self.metrics.aggregate()

    def _parse_file(self, fname, fdata, new_files_list):
        try:
            # parse the current file
            data = fdata.read()
            lines = data.splitlines()
            self.metrics.begin(fname)
            self.metrics.count_locs(lines)
            # nosec_lines is a dict of line number -> set of tests to ignore
            #                                         for the line
            nosec_lines = dict()
            try:
                fdata.seek(0)
                tokens = tokenize.tokenize(fdata.readline)

                if not self.ignore_nosec:
                    for toktype, tokval, (lineno, _), _, _ in tokens:
                        if toktype == tokenize.COMMENT:
                            nosec_lines[lineno] = _parse_nosec_comment(tokval)

            except tokenize.TokenError:
                pass
            score = self._execute_ast_visitor(fname, fdata, data, nosec_lines)
            self.scores.append(score)
            self.metrics.count_issues([score])
        except KeyboardInterrupt:
            sys.exit(2)
        except SyntaxError:
            self.skipped.append(
                (fname, "syntax error while parsing AST from file")
            )
            new_files_list.remove(fname)
        except Exception as e:
            LOG.error(
                "Exception occurred when executing tests against %s.", fname
            )
            if not LOG.isEnabledFor(logging.DEBUG):
                LOG.error(
                    'Run "bandit --debug %s" to see the full traceback.', fname
                )

            self.skipped.append((fname, "exception while scanning file"))
            new_files_list.remove(fname)
            LOG.debug("  Exception string: %s", e)
            LOG.debug("  Exception traceback: %s", traceback.format_exc())

    def _execute_ast_visitor(self, fname, fdata, data, nosec_lines):
        """Execute AST parse on each file

        :param fname: The name of the file being parsed
        :param data: Original file contents
        :param lines: The lines of code to process
        :return: The accumulated test score
        """
        score = []
        res = b_node_visitor.BanditNodeVisitor(
            fname,
            fdata,
            self.b_ma,
            self.b_ts,
            self.debug,
            nosec_lines,
            self.metrics,
        )

        score = res.process(data)
        self.results.extend(res.tester.results)
        return score


def _get_files_from_dir(
    files_dir, included_globs=None, excluded_path_strings=None
):
    if not included_globs:
        included_globs = ["*.py"]
    if not excluded_path_strings:
        excluded_path_strings = []

    files_list = set()
    excluded_files = set()

    for root, _, files in os.walk(files_dir):
        for filename in files:
            path = os.path.join(root, filename)
            if _is_file_included(path, included_globs, excluded_path_strings):
                files_list.add(path)
            else:
                excluded_files.add(path)

    return files_list, excluded_files


def _is_file_included(
    path, included_globs, excluded_path_strings, enforce_glob=True
):
    """Determine if a file should be included based on filename

    This utility function determines if a file should be included based
    on the file name, a list of parsed extensions, excluded paths, and a flag
    specifying whether extensions should be enforced.

    :param path: Full path of file to check
    :param parsed_extensions: List of parsed extensions
    :param excluded_paths: List of paths (globbing supported) from which we
        should not include files
    :param enforce_glob: Can set to false to bypass extension check
    :return: Boolean indicating whether a file should be included
    """
    return_value = False

    # if this is matches a glob of files we look at, and it isn't in an
    # excluded path
    if _matches_glob_list(path, included_globs) or not enforce_glob:
        if not _matches_glob_list(path, excluded_path_strings) and not any(
            x in path for x in excluded_path_strings
        ):
            return_value = True

    return return_value


def _matches_glob_list(filename, glob_list):
    for glob in glob_list:
        if fnmatch.fnmatch(filename, glob):
            return True
    return False


def _compare_baseline_results(baseline, results):
    """Compare a baseline list of issues to list of results

    This function compares a baseline set of issues to a current set of issues
    to find results that weren't present in the baseline.

    :param baseline: Baseline list of issues
    :param results: Current list of issues
    :return: List of unmatched issues
    """
    return [a for a in results if a not in baseline]


def _find_candidate_matches(unmatched_issues, results_list):
    """Returns a dictionary with issue candidates

    For example, let's say we find a new command injection issue in a file
    which used to have two.  Bandit can't tell which of the command injection
    issues in the file are new, so it will show all three.  The user should
    be able to pick out the new one.

    :param unmatched_issues: List of issues that weren't present before
    :param results_list: main list of current Bandit findings
    :return: A dictionary with a list of candidates for each issue
    """

    issue_candidates = collections.OrderedDict()

    for unmatched in unmatched_issues:
        issue_candidates[unmatched] = [
            i for i in results_list if unmatched == i
        ]

    return issue_candidates


def _find_test_id_from_nosec_string(extman, match):
    test_id = extman.check_id(match)
    if test_id:
        return match
    # Finding by short_id didn't work, let's check the test name
    test_id = extman.get_test_id(match)
    if not test_id:
        # Name and short id didn't work:
        LOG.warning(
            "Test in comment: %s is not a test name or id, ignoring", match
        )
    return test_id  # We want to return None or the string here regardless


def _parse_nosec_comment(comment):
    found_no_sec_comment = NOSEC_COMMENT.search(comment)
    if not found_no_sec_comment:
        # there was no nosec comment
        return None

    matches = found_no_sec_comment.groupdict()
    nosec_tests = matches.get("tests", set())

    # empty set indicates that there was a nosec comment without specific
    # test ids or names
    test_ids = set()
    if nosec_tests:
        extman = extension_loader.MANAGER
        # lookup tests by short code or name
        for test in NOSEC_COMMENT_TESTS.finditer(nosec_tests):
            test_match = test.group(1)
            test_id = _find_test_id_from_nosec_string(extman, test_match)
            if test_id:
                test_ids.add(test_id)

    return test_ids


================================================
FILE: bandit/core/meta_ast.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import collections
import logging

LOG = logging.getLogger(__name__)


class BanditMetaAst:
    nodes = collections.OrderedDict()

    def __init__(self):
        pass

    def add_node(self, node, parent_id, depth):
        """Add a node to the AST node collection

        :param node: The AST node to add
        :param parent_id: The ID of the node's parent
        :param depth: The depth of the node
        :return: -
        """
        node_id = hex(id(node))
        LOG.debug("adding node : %s [%s]", node_id, depth)
        self.nodes[node_id] = {
            "raw": node,
            "parent_id": parent_id,
            "depth": depth,
        }

    def __str__(self):
        """Dumps a listing of all of the nodes

        Dumps a listing of all of the nodes for debugging purposes
        :return: -
        """
        tmpstr = ""
        for k, v in self.nodes.items():
            tmpstr += f"Node: {k}\n"
            tmpstr += f"\t{str(v)}\n"
        tmpstr += f"Length: {len(self.nodes)}\n"
        return tmpstr


================================================
FILE: bandit/core/metrics.py
================================================
#
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import collections

from bandit.core import constants


class Metrics:
    """Bandit metric gathering.

    This class is a singleton used to gather and process metrics collected when
    processing a code base with bandit. Metric collection is stateful, that
    is, an active metric block will be set when requested and all subsequent
    operations will effect that metric block until it is replaced by a setting
    a new one.
    """

    def __init__(self):
        self.data = dict()
        self.data["_totals"] = {
            "loc": 0,
            "nosec": 0,
            "skipped_tests": 0,
        }

        # initialize 0 totals for criteria and rank; this will be reset later
        for rank in constants.RANKING:
            for criteria in constants.CRITERIA:
                self.data["_totals"][f"{criteria[0]}.{rank}"] = 0

    def begin(self, fname):
        """Begin a new metric block.

        This starts a new metric collection name "fname" and makes is active.
        :param fname: the metrics unique name, normally the file name.
        """
        self.data[fname] = {
            "loc": 0,
            "nosec": 0,
            "skipped_tests": 0,
        }
        self.current = self.data[fname]

    def note_nosec(self, num=1):
        """Note a "nosec" comment.

        Increment the currently active metrics nosec count.
        :param num: number of nosecs seen, defaults to 1
        """
        self.current["nosec"] += num

    def note_skipped_test(self, num=1):
        """Note a "nosec BXXX, BYYY, ..." comment.

        Increment the currently active metrics skipped_tests count.
        :param num: number of skipped_tests seen, defaults to 1
        """
        self.current["skipped_tests"] += num

    def count_locs(self, lines):
        """Count lines of code.

        We count lines that are not empty and are not comments. The result is
        added to our currently active metrics loc count (normally this is 0).

        :param lines: lines in the file to process
        """

        def proc(line):
            tmp = line.strip()
            return bool(tmp and not tmp.startswith(b"#"))

        self.current["loc"] += sum(proc(line) for line in lines)

    def count_issues(self, scores):
        self.current.update(self._get_issue_counts(scores))

    def aggregate(self):
        """Do final aggregation of metrics."""
        c = collections.Counter()
        for fname in self.data:
            c.update(self.data[fname])
        self.data["_totals"] = dict(c)

    @staticmethod
    def _get_issue_counts(scores):
        """Get issue counts aggregated by confidence/severity rankings.

        :param scores: list of scores to aggregate / count
        :return: aggregated total (count) of issues identified
        """
        issue_counts = {}
        for score in scores:
            for criteria, _ in constants.CRITERIA:
                for i, rank in enumerate(constants.RANKING):
                    label = f"{criteria}.{rank}"
                    if label not in issue_counts:
                        issue_counts[label] = 0
                        count = (
                            score[criteria][i]
                            // constants.RANKING_VALUES[rank]
                        )
                        issue_counts[label] += count
        return issue_counts


================================================
FILE: bandit/core/node_visitor.py
================================================
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
import ast
import logging
import operator

from bandit.core import constants
from bandit.core import tester as b_tester
from bandit.core import utils as b_utils

LOG = logging.getLogger(__name__)


class BanditNodeVisitor:
    def __init__(
        self, fname, fdata, metaast, testset, debug, nosec_lines, metrics
    ):
        self.debug = debug
        self.nosec_lines = nosec_lines
        self.scores = {
            "SEVERITY": [0] * len(constants.RANKING),
            "CONFIDENCE": [0] * len(constants.RANKING),
        }
        self.depth = 0
        self.fname = fname
        self.fdata = fdata
        self.metaast = metaast
        self.testset = testset
        self.imports = set()
        self.import_aliases = {}
        self.tester = b_tester.BanditTester(
            self.testset, self.debug, nosec_lines, metrics
        )

        # in some cases we can't determine a qualified name
        try:
            self.namespace = b_utils.get_module_qualname_from_path(fname)
        except b_utils.InvalidModulePath:
            LOG.warning(
                "Unable to find qualified name for module: %s", self.fname
            )
            self.namespace = ""
        LOG.debug("Module qualified name: %s", self.namespace)
        self.metrics = metrics

    def visit_ClassDef(self, node):
        """Visitor for AST ClassDef node

        Add class name to current namespace for all descendants.
        :param node: Node being inspected
        :return: -
        """
        # For all child nodes, add this class name to current namespace
        self.namespace = b_utils.namespace_path_join(self.namespace, node.name)

    def visit_FunctionDef(self, node):
        """Visitor for AST FunctionDef nodes

        add relevant information about the node to
        the context for use in tests which inspect function definitions.
        Add the function name to the current namespace for all descendants.
        :param node: The node that is being inspected
        :return: -
        """

        self.context["function"] = node
        qualname = self.namespace + "." + b_utils.get_func_name(node)
        name = qualname.split(".")[-1]

        self.context["qualname"] = qualname
        self.context["name"] = name

        # For all child nodes and any tests run, add this function name to
        # current namespace
        self.namespace = b_utils.namespace_path_join(self.namespace, name)
        self.update_scores(self.tester.run_tests(self.context, "FunctionDef"))

    def visit_Call(self, node):
        """Visitor for AST Call nodes

        add relevant information about the node to
        the context for use in tests which inspect function calls.
        :param node: The node that is being inspected
        :return: -
        """

        self.context["call"] = node
        qualname = b_utils.get_call_name(node, self.import_aliases)
        name = qualname.split(".")[-1]

        self.context["qualname"] = qualname
        self.context["name"] = name

        self.update_scores(self.tester.run_tests(self.context, "Call"))

    def visit_Import(self, node):
        """Visitor for AST Import nodes

        add relevant information about node to
        the context for use in tests which inspect imports.
        :param node: The node that is being inspected
        :return: -
        """
        for nodename in node.names:
            if nodename.asname:
                self.import_aliases[nodename.asname] = nodename.name
            self.imports.add(nodename.name)
            self.context["module"] = nodename.name
        self.update_scores(self.tester.run_tests(self.context, "Import"))

    def visit_ImportFrom(self, node):
        """Visitor for AST ImportFrom nodes

        add relevant information about node to
        the context for use in tests which inspect imports.
        :param node: The node that is being inspected
        :return: -
        """
        module = node.module
        if module is None:
            return self.visit_Import(node)

        for nodename in node.names:
            # TODO(ljfisher) Names in import_aliases could be overridden
            #      by local definitions. If this occurs bandit will see the
            #      name in import_aliases instead of the local definition.
            #      We need better tracking of names.
            if nodename.asname:
                self.import_aliases[nodename.asname] = (
                    module + "." + nodename.name
                )
            else:
                # Even if import is not aliased we need an entry that maps
                # name to module.name.  For example, with 'from a import b'
                # b should be aliased to the qualified name a.b
                self.import_aliases[nodename.name] = (
                    module + "." + nodename.name
                )
            self.imports.add(module + "." + nodename.name)
            self.context["module"] = module
            self.context["name"] = nodename.name
        self.update_scores(self.tester.run_tests(self.context, "ImportFrom"))

    def visit_Constant(self, node):
        """Visitor for AST Constant nodes

        call the appropriate method for the node type.
        this maintains compatibility with <3.6 and 3.8+

        This code is heavily influenced by Anthony Sottile (@asottile) here:
        https://bugs.python.org/msg342486

        :param node: The node that is being inspected
        :return: -
        """
        if isinstance(node.value, str):
            self.visit_Str(node)
        elif isinstance(node.value, bytes):
            self.visit_Bytes(node)

    def visit_Str(self, node):
        """Visitor for AST String nodes

        add relevant information about node to
        the context for use in tests which inspect strings.
        :param node: The node that is being inspected
        :return: -
        """
        self.context["str"] = node.value
        if not isinstance(node._bandit_parent, ast.Expr):  # docstring
            self.context["linerange"] = b_utils.linerange(node._bandit_parent)
            self.update_scores(self.tester.run_tests(self.context, "Str"))

    def visit_Bytes(self, node):
        """Visitor for AST Bytes nodes

        add relevant information about node to
        the context for use in tests which inspect strings.
        :param node: The node that is being inspected
        :return: -
        """
        self.context["bytes"] = node.value
        if not isinstance(node._bandit_parent, ast.Expr):  # docstring
            self.context["linerange"] = b_utils.linerange(node._bandit_parent)
            self.update_scores(self.tester.run_tests(self.context, "Bytes"))

    def pre_visit(self, node):
        self.context = {}
        self.context["imports"] = self.imports
        self.context["import_aliases"] = self.import_aliases

        if self.debug:
            LOG.debug(ast.dump(node))
            self.metaast.add_node(node, "", self.depth)

        if hasattr(node, "lineno"):
            self.context["lineno"] = node.lineno

        if hasattr(node, "col_offset"):
            self.context["col_offset"] = node.col_offset
        if hasattr(node, "end_col_offset"):
            self.context["end_col_offset"] = node.end_col_offset

        self.context["node"] = node
        self.context["linerange"] = b_utils.linerange(node)
        self.context["filename"] = self.fname
        self.context["file_data"] = self.fdata

        LOG.debug(
            "entering: %s %s [%s]", hex(id(node)), type(node), self.depth
        )
        self.depth += 1
        LOG.debug(self.context)
        return True

    def visit(self, node):
        name = node.__class__.__name__
        method = "visit_" + name
        visitor = getattr(self, method, None)
        if visitor is not None:
            if self.debug:
                LOG.debug("%s called (%s)", method, ast.dump(node))
            visitor(node)
        else:
            self.update_scores(self.tester.run_tests(self.context, name))

    def post_visit(self, node):
        self.depth -= 1
        LOG.debug("%s\texiting : %s", self.depth, hex(id(node)))

        # HACK(tkelsey): this is needed to clean up post-recursion stuff that
        # gets setup in the visit methods for these node types.
        if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
            self.namespace = b_utils.namespace_path_split(self.namespace)[0]

    def generic_visit(self, node):
        """Drive the visitor."""
        for _, value in ast.iter_fields(node):
            if isinstance(value, list):
                max_idx = len(value) - 1
                for idx, item in enumerate(value):
                    if isinstance(item, ast.AST):
                        if idx < max_idx:
                            item._bandit_sibling = value[idx + 1]
                        else:
                            item._bandit_sibling = None
                        item._bandit_parent = node

                        if self.pre_visit(item):
                            self.visit(item)
              
Download .txt
gitextract_siphom_i/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── Feature_request.md
│   │   ├── bug-report.yml
│   │   └── config.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── build-publish-image.yml
│       ├── dependency-review.yml
│       ├── publish-to-pypi.yml
│       ├── publish-to-test-pypi.yml
│       └── pythonpackage.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .pre-commit-hooks.yaml
├── .readthedocs.yaml
├── .stestr.conf
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.rst
├── SECURITY.md
├── bandit/
│   ├── __init__.py
│   ├── __main__.py
│   ├── blacklists/
│   │   ├── __init__.py
│   │   ├── calls.py
│   │   ├── imports.py
│   │   └── utils.py
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── baseline.py
│   │   ├── config_generator.py
│   │   └── main.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── blacklisting.py
│   │   ├── config.py
│   │   ├── constants.py
│   │   ├── context.py
│   │   ├── docs_utils.py
│   │   ├── extension_loader.py
│   │   ├── issue.py
│   │   ├── manager.py
│   │   ├── meta_ast.py
│   │   ├── metrics.py
│   │   ├── node_visitor.py
│   │   ├── test_properties.py
│   │   ├── test_set.py
│   │   ├── tester.py
│   │   └── utils.py
│   ├── formatters/
│   │   ├── __init__.py
│   │   ├── csv.py
│   │   ├── custom.py
│   │   ├── html.py
│   │   ├── json.py
│   │   ├── sarif.py
│   │   ├── screen.py
│   │   ├── text.py
│   │   ├── utils.py
│   │   ├── xml.py
│   │   └── yaml.py
│   └── plugins/
│       ├── __init__.py
│       ├── app_debug.py
│       ├── asserts.py
│       ├── crypto_request_no_cert_validation.py
│       ├── django_sql_injection.py
│       ├── django_xss.py
│       ├── exec.py
│       ├── general_bad_file_permissions.py
│       ├── general_bind_all_interfaces.py
│       ├── general_hardcoded_password.py
│       ├── general_hardcoded_tmp.py
│       ├── hashlib_insecure_functions.py
│       ├── huggingface_unsafe_download.py
│       ├── injection_paramiko.py
│       ├── injection_shell.py
│       ├── injection_sql.py
│       ├── injection_wildcard.py
│       ├── insecure_ssl_tls.py
│       ├── jinja2_templates.py
│       ├── logging_config_insecure_listen.py
│       ├── mako_templates.py
│       ├── markupsafe_markup_xss.py
│       ├── pytorch_load.py
│       ├── request_without_timeout.py
│       ├── snmp_security_check.py
│       ├── ssh_no_host_key_verification.py
│       ├── tarfile_unsafe_members.py
│       ├── trojansource.py
│       ├── try_except_continue.py
│       ├── try_except_pass.py
│       ├── weak_cryptographic_key.py
│       └── yaml_load.py
├── doc/
│   ├── requirements.txt
│   └── source/
│       ├── blacklists/
│       │   ├── blacklist_calls.rst
│       │   ├── blacklist_imports.rst
│       │   └── index.rst
│       ├── ci-cd/
│       │   ├── github-actions.rst
│       │   └── index.rst
│       ├── conf.py
│       ├── config.rst
│       ├── faq.rst
│       ├── formatters/
│       │   ├── csv.rst
│       │   ├── custom.rst
│       │   ├── html.rst
│       │   ├── index.rst
│       │   ├── json.rst
│       │   ├── sarif.rst
│       │   ├── screen.rst
│       │   ├── text.rst
│       │   ├── xml.rst
│       │   └── yaml.rst
│       ├── index.rst
│       ├── integrations.rst
│       ├── man/
│       │   └── bandit.rst
│       ├── plugins/
│       │   ├── b101_assert_used.rst
│       │   ├── b102_exec_used.rst
│       │   ├── b103_set_bad_file_permissions.rst
│       │   ├── b104_hardcoded_bind_all_interfaces.rst
│       │   ├── b105_hardcoded_password_string.rst
│       │   ├── b106_hardcoded_password_funcarg.rst
│       │   ├── b107_hardcoded_password_default.rst
│       │   ├── b108_hardcoded_tmp_directory.rst
│       │   ├── b109_password_config_option_not_marked_secret.rst
│       │   ├── b110_try_except_pass.rst
│       │   ├── b111_execute_with_run_as_root_equals_true.rst
│       │   ├── b112_try_except_continue.rst
│       │   ├── b113_request_without_timeout.rst
│       │   ├── b201_flask_debug_true.rst
│       │   ├── b202_tarfile_unsafe_members.rst
│       │   ├── b324_hashlib.rst
│       │   ├── b501_request_with_no_cert_validation.rst
│       │   ├── b502_ssl_with_bad_version.rst
│       │   ├── b503_ssl_with_bad_defaults.rst
│       │   ├── b504_ssl_with_no_version.rst
│       │   ├── b505_weak_cryptographic_key.rst
│       │   ├── b506_yaml_load.rst
│       │   ├── b507_ssh_no_host_key_verification.rst
│       │   ├── b508_snmp_insecure_version.rst
│       │   ├── b509_snmp_weak_cryptography.rst
│       │   ├── b601_paramiko_calls.rst
│       │   ├── b602_subprocess_popen_with_shell_equals_true.rst
│       │   ├── b603_subprocess_without_shell_equals_true.rst
│       │   ├── b604_any_other_function_with_shell_equals_true.rst
│       │   ├── b605_start_process_with_a_shell.rst
│       │   ├── b606_start_process_with_no_shell.rst
│       │   ├── b607_start_process_with_partial_path.rst
│       │   ├── b608_hardcoded_sql_expressions.rst
│       │   ├── b609_linux_commands_wildcard_injection.rst
│       │   ├── b610_django_extra_used.rst
│       │   ├── b611_django_rawsql_used.rst
│       │   ├── b612_logging_config_insecure_listen.rst
│       │   ├── b613_trojansource.rst
│       │   ├── b614_pytorch_load.rst
│       │   ├── b615_huggingface_unsafe_download.rst
│       │   ├── b701_jinja2_autoescape_false.rst
│       │   ├── b702_use_of_mako_templates.rst
│       │   ├── b703_django_mark_safe.rst
│       │   ├── b704_markupsafe_markup_xss.rst
│       │   └── index.rst
│       └── start.rst
├── docker/
│   └── Dockerfile
├── examples/
│   ├── __init__.py
│   ├── assert.py
│   ├── binding.py
│   ├── cipher-modes.py
│   ├── ciphers.py
│   ├── crypto-md5.py
│   ├── dill.py
│   ├── django_sql_injection_extra.py
│   ├── django_sql_injection_raw.py
│   ├── eval.py
│   ├── exec.py
│   ├── flask_debug.py
│   ├── ftplib.py
│   ├── hardcoded-passwords.py
│   ├── hardcoded-tmp.py
│   ├── hashlib_new_insecure_functions.py
│   ├── httpoxy_cgihandler.py
│   ├── httpoxy_twisted_directory.py
│   ├── httpoxy_twisted_script.py
│   ├── huggingface_unsafe_download.py
│   ├── imports-aliases.py
│   ├── imports-from.py
│   ├── imports-function.py
│   ├── imports-with-importlib.py
│   ├── imports.py
│   ├── init-py-test/
│   │   ├── __init__.py
│   │   └── subdirectory-okay.py
│   ├── jinja2_templating.py
│   ├── jsonpickle.py
│   ├── logging_config_insecure_listen.py
│   ├── long_set.py
│   ├── mako_templating.py
│   ├── mark_safe.py
│   ├── mark_safe_insecure.py
│   ├── mark_safe_secure.py
│   ├── markupsafe_markup_xss.py
│   ├── markupsafe_markup_xss_allowed_calls.py
│   ├── markupsafe_markup_xss_extend_markup_names.py
│   ├── marshal_deserialize.py
│   ├── mktemp.py
│   ├── multiline_statement.py
│   ├── new_candidates-all.py
│   ├── new_candidates-none.py
│   ├── new_candidates-nosec.py
│   ├── new_candidates-some.py
│   ├── no_host_key_verification.py
│   ├── nonsense.py
│   ├── nonsense2.py
│   ├── nosec.py
│   ├── okay.py
│   ├── os-chmod.py
│   ├── os-exec.py
│   ├── os-popen.py
│   ├── os-spawn.py
│   ├── os-startfile.py
│   ├── os_system.py
│   ├── pandas_read_pickle.py
│   ├── paramiko_injection.py
│   ├── partial_path_process.py
│   ├── pickle_deserialize.py
│   ├── popen_wrappers.py
│   ├── pycrypto.py
│   ├── pycryptodome.py
│   ├── pyghmi.py
│   ├── pytorch_load.py
│   ├── random_module.py
│   ├── requests-missing-timeout.py
│   ├── requests-ssl-verify-disabled.py
│   ├── shelve_open.py
│   ├── skip.py
│   ├── snmp.py
│   ├── sql_multiline_statements.py
│   ├── sql_statements.py
│   ├── ssl-insecure-version.py
│   ├── subprocess_shell.py
│   ├── tarfile_extractall.py
│   ├── telnetlib.py
│   ├── trojansource.py
│   ├── trojansource_latin1.py
│   ├── try_except_continue.py
│   ├── try_except_pass.py
│   ├── unverified_context.py
│   ├── urlopen.py
│   ├── weak_cryptographic_key_sizes.py
│   ├── wildcard-injection.py
│   ├── xml_etree_celementtree.py
│   ├── xml_etree_elementtree.py
│   ├── xml_expatbuilder.py
│   ├── xml_expatreader.py
│   ├── xml_minidom.py
│   ├── xml_pulldom.py
│   ├── xml_sax.py
│   ├── xml_xmlrpc.py
│   └── yaml_load.py
├── funding.json
├── pylintrc
├── requirements.txt
├── scripts/
│   └── main.py
├── setup.cfg
├── setup.py
├── test-requirements.txt
├── tests/
│   ├── __init__.py
│   ├── functional/
│   │   ├── __init__.py
│   │   ├── test_baseline.py
│   │   ├── test_functional.py
│   │   └── test_runtime.py
│   └── unit/
│       ├── __init__.py
│       ├── cli/
│       │   ├── __init__.py
│       │   ├── test_baseline.py
│       │   ├── test_config_generator.py
│       │   └── test_main.py
│       ├── core/
│       │   ├── __init__.py
│       │   ├── test_blacklisting.py
│       │   ├── test_config.py
│       │   ├── test_context.py
│       │   ├── test_docs_util.py
│       │   ├── test_issue.py
│       │   ├── test_manager.py
│       │   ├── test_meta_ast.py
│       │   ├── test_test_set.py
│       │   └── test_util.py
│       └── formatters/
│           ├── __init__.py
│           ├── test_csv.py
│           ├── test_custom.py
│           ├── test_html.py
│           ├── test_json.py
│           ├── test_sarif.py
│           ├── test_screen.py
│           ├── test_text.py
│           ├── test_xml.py
│           └── test_yaml.py
└── tox.ini
Download .txt
SYMBOL INDEX (709 symbols across 107 files)

FILE: bandit/blacklists/calls.py
  function gen_blacklist (line 346) | def gen_blacklist():

FILE: bandit/blacklists/imports.py
  function gen_blacklist (line 234) | def gen_blacklist():

FILE: bandit/blacklists/utils.py
  function build_conf_dict (line 8) | def build_conf_dict(name, bid, cwe, qualnames, message, level="MEDIUM"):

FILE: bandit/cli/baseline.py
  function main (line 39) | def main():
  function baseline_setup (line 135) | def baseline_setup():
  function init_logger (line 146) | def init_logger():
  function initialize (line 159) | def initialize():

FILE: bandit/cli/config_generator.py
  function init_logger (line 50) | def init_logger():
  function parse_args (line 62) | def parse_args():
  function get_config_settings (line 124) | def get_config_settings():
  function main (line 142) | def main():

FILE: bandit/cli/main.py
  function _init_logger (line 23) | def _init_logger(log_level=logging.INFO, log_format=None):
  function _get_options_from_ini (line 46) | def _get_options_from_ini(ini_path, target):
  function _init_extensions (line 78) | def _init_extensions():
  function _log_option_source (line 84) | def _log_option_source(default_val, arg_val, ini_val, option_name):
  function _running_under_virtualenv (line 104) | def _running_under_virtualenv():
  function _get_profile (line 111) | def _get_profile(config, profile_name, config_path):
  function _log_info (line 125) | def _log_info(args, profile):
  function main (line 134) | def main():

FILE: bandit/core/blacklisting.py
  function report_issue (line 10) | def report_issue(check, name):
  function blacklist (line 21) | def blacklist(context, config):

FILE: bandit/core/config.py
  class BanditConfig (line 25) | class BanditConfig:
    method __init__ (line 26) | def __init__(self, config_file=None):
    method get_option (line 84) | def get_option(self, option_string):
    method get_setting (line 103) | def get_setting(self, setting_name):
    method config (line 110) | def config(self):
    method _init_settings (line 117) | def _init_settings(self):
    method _init_plugin_name_pattern (line 129) | def _init_plugin_name_pattern(self):
    method convert_legacy_config (line 136) | def convert_legacy_config(self):
    method convert_names_to_ids (line 146) | def convert_names_to_ids(self):
    method convert_legacy_blacklist_data (line 166) | def convert_legacy_blacklist_data(self):
    method convert_legacy_blacklist_tests (line 197) | def convert_legacy_blacklist_tests(profiles, bad_imports, bad_calls):
    method validate (line 235) | def validate(self, path):

FILE: bandit/core/context.py
  class Context (line 10) | class Context:
    method __init__ (line 11) | def __init__(self, context_object=None):
    method __repr__ (line 22) | def __repr__(self):
    method call_args (line 40) | def call_args(self):
    method call_args_count (line 55) | def call_args_count(self):
    method call_function_name (line 66) | def call_function_name(self):
    method call_function_name_qual (line 74) | def call_function_name_qual(self):
    method call_keywords (line 82) | def call_keywords(self):
    method node (line 101) | def node(self):
    method string_val (line 109) | def string_val(self):
    method bytes_val (line 117) | def bytes_val(self):
    method string_val_as_escaped_bytes (line 125) | def string_val_as_escaped_bytes(self):
    method statement (line 148) | def statement(self):
    method function_def_defaults_qual (line 156) | def function_def_defaults_qual(self):
    method _get_literal_value (line 175) | def _get_literal_value(self, literal):
    method get_call_arg_value (line 218) | def get_call_arg_value(self, argument_name):
    method check_call_arg_value (line 227) | def check_call_arg_value(self, argument_name, argument_values=None):
    method get_lineno_for_call_arg (line 250) | def get_lineno_for_call_arg(self, argument_name):
    method get_call_arg_at_position (line 263) | def get_call_arg_at_position(self, position_num):
    method is_module_being_imported (line 276) | def is_module_being_imported(self, module):
    method is_module_imported_exact (line 284) | def is_module_imported_exact(self, module):
    method is_module_imported_like (line 292) | def is_module_imported_like(self, module):
    method filename (line 307) | def filename(self):
    method file_data (line 311) | def file_data(self):
    method import_aliases (line 315) | def import_aliases(self):

FILE: bandit/core/docs_utils.py
  function get_url (line 8) | def get_url(bid):

FILE: bandit/core/extension_loader.py
  class Manager (line 13) | class Manager:
    method __init__ (line 17) | def __init__(
    method load_formatters (line 28) | def load_formatters(self, formatters_namespace):
    method load_plugins (line 37) | def load_plugins(self, plugins_namespace):
    method get_test_id (line 59) | def get_test_id(self, test_name):
    method load_blacklists (line 66) | def load_blacklists(self, blacklist_namespace):
    method validate_profile (line 86) | def validate_profile(self, profile):
    method check_id (line 102) | def check_id(self, test):

FILE: bandit/core/issue.py
  class Cwe (line 10) | class Cwe:
    method __init__ (line 38) | def __init__(self, id=NOTSET):
    method link (line 41) | def link(self):
    method __str__ (line 47) | def __str__(self):
    method as_dict (line 53) | def as_dict(self):
    method as_jsons (line 60) | def as_jsons(self):
    method from_dict (line 63) | def from_dict(self, data):
    method __eq__ (line 69) | def __eq__(self, other):
    method __ne__ (line 72) | def __ne__(self, other):
    method __hash__ (line 75) | def __hash__(self):
  class Issue (line 79) | class Issue:
    method __init__ (line 80) | def __init__(
    method __str__ (line 108) | def __str__(self):
    method __eq__ (line 124) | def __eq__(self, other):
    method __ne__ (line 141) | def __ne__(self, other):
    method __hash__ (line 144) | def __hash__(self):
    method filter (line 147) | def filter(self, severity, confidence):
    method get_code (line 169) | def get_code(self, max_lines=3, tabbed=False):
    method as_dict (line 201) | def as_dict(self, with_code=True, max_lines=3):
    method from_dict (line 221) | def from_dict(self, data, with_code=True):
  function cwe_from_dict (line 236) | def cwe_from_dict(data):
  function issue_from_dict (line 242) | def issue_from_dict(data):

FILE: bandit/core/manager.py
  class BanditManager (line 32) | class BanditManager:
    method __init__ (line 35) | def __init__(
    method get_skipped (line 75) | def get_skipped(self):
    method get_issue_list (line 85) | def get_issue_list(
    method populate_baseline (line 90) | def populate_baseline(self, data):
    method filter_results (line 105) | def filter_results(self, sev_filter, conf_filter):
    method results_count (line 130) | def results_count(
    method output_results (line 141) | def output_results(
    method discover_files (line 200) | def discover_files(self, targets, recursive=False, excluded_paths=""):
    method run_tests (line 261) | def run_tests(self):
    method _parse_file (line 301) | def _parse_file(self, fname, fdata, new_files_list):
    method _execute_ast_visitor (line 346) | def _execute_ast_visitor(self, fname, fdata, data, nosec_lines):
  function _get_files_from_dir (line 370) | def _get_files_from_dir(
  function _is_file_included (line 392) | def _is_file_included(
  function _matches_glob_list (line 421) | def _matches_glob_list(filename, glob_list):
  function _compare_baseline_results (line 428) | def _compare_baseline_results(baseline, results):
  function _find_candidate_matches (line 441) | def _find_candidate_matches(unmatched_issues, results_list):
  function _find_test_id_from_nosec_string (line 464) | def _find_test_id_from_nosec_string(extman, match):
  function _parse_nosec_comment (line 478) | def _parse_nosec_comment(comment):

FILE: bandit/core/meta_ast.py
  class BanditMetaAst (line 11) | class BanditMetaAst:
    method __init__ (line 14) | def __init__(self):
    method add_node (line 17) | def add_node(self, node, parent_id, depth):
    method __str__ (line 33) | def __str__(self):

FILE: bandit/core/metrics.py
  class Metrics (line 10) | class Metrics:
    method __init__ (line 20) | def __init__(self):
    method begin (line 33) | def begin(self, fname):
    method note_nosec (line 46) | def note_nosec(self, num=1):
    method note_skipped_test (line 54) | def note_skipped_test(self, num=1):
    method count_locs (line 62) | def count_locs(self, lines):
    method count_issues (line 77) | def count_issues(self, scores):
    method aggregate (line 80) | def aggregate(self):
    method _get_issue_counts (line 88) | def _get_issue_counts(scores):

FILE: bandit/core/node_visitor.py
  class BanditNodeVisitor (line 16) | class BanditNodeVisitor:
    method __init__ (line 17) | def __init__(
    method visit_ClassDef (line 48) | def visit_ClassDef(self, node):
    method visit_FunctionDef (line 58) | def visit_FunctionDef(self, node):
    method visit_Call (line 80) | def visit_Call(self, node):
    method visit_Import (line 98) | def visit_Import(self, node):
    method visit_ImportFrom (line 113) | def visit_ImportFrom(self, node):
    method visit_Constant (line 146) | def visit_Constant(self, node):
    method visit_Str (line 163) | def visit_Str(self, node):
    method visit_Bytes (line 176) | def visit_Bytes(self, node):
    method pre_visit (line 189) | def pre_visit(self, node):
    method visit (line 218) | def visit(self, node):
    method post_visit (line 229) | def post_visit(self, node):
    method generic_visit (line 238) | def generic_visit(self, node):
    method update_scores (line 264) | def update_scores(self, scores):
    method process (line 278) | def process(self, data):

FILE: bandit/core/test_properties.py
  function checks (line 12) | def checks(*args):
  function takes_config (line 31) | def takes_config(*args):
  function test_id (line 53) | def test_id(id_val):
  function accepts_baseline (line 67) | def accepts_baseline(*args):

FILE: bandit/core/test_set.py
  class BanditTestSet (line 14) | class BanditTestSet:
    method __init__ (line 15) | def __init__(self, config, profile=None):
    method _get_filter (line 27) | def _get_filter(config, profile):
    method _load_builtins (line 59) | def _load_builtins(self, filtering, profile):
    method _load_tests (line 88) | def _load_tests(self, config, plugins):
    method get_tests (line 108) | def get_tests(self, checktype):

FILE: bandit/core/tester.py
  class BanditTester (line 17) | class BanditTester:
    method __init__ (line 18) | def __init__(self, testset, debug, nosec_lines, metrics):
    method run_tests (line 26) | def run_tests(self, raw_context, checktype):
    method _get_nosecs_from_contexts (line 127) | def _get_nosecs_from_contexts(self, context, test_result=None):
    method report_error (line 157) | def report_error(test, context, error):

FILE: bandit/core/utils.py
  function _get_attr_qual_name (line 21) | def _get_attr_qual_name(node, aliases):
  function get_call_name (line 49) | def get_call_name(node, aliases):
  function get_func_name (line 60) | def get_func_name(node):
  function get_qual_attr (line 64) | def get_qual_attr(node, aliases):
  function deepgetattr (line 82) | def deepgetattr(obj, attr):
  class InvalidModulePath (line 89) | class InvalidModulePath(Exception):
  class ConfigError (line 93) | class ConfigError(Exception):
    method __init__ (line 96) | def __init__(self, message, config_file):
  class ProfileNotFound (line 102) | class ProfileNotFound(Exception):
    method __init__ (line 105) | def __init__(self, config_file, profile):
  function warnings_formatter (line 115) | def warnings_formatter(
  function get_module_qualname_from_path (line 122) | def get_module_qualname_from_path(path):
  function namespace_path_join (line 157) | def namespace_path_join(base, name):
  function namespace_path_split (line 172) | def namespace_path_split(path):
  function escaped_bytes_representation (line 186) | def escaped_bytes_representation(b):
  function calc_linerange (line 199) | def calc_linerange(node):
  function linerange (line 219) | def linerange(node):
  function concat_string (line 273) | def concat_string(node, stop=None):
  function get_called_name (line 315) | def get_called_name(node):
  function get_path_for_function (line 332) | def get_path_for_function(f):
  function parse_ini_file (line 355) | def parse_ini_file(f_loc):
  function check_ast_node (line 370) | def check_ast_node(name):
  function get_nosec (line 393) | def get_nosec(nosec_lines, context):

FILE: bandit/formatters/csv.py
  function report (line 41) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/custom.py
  class SafeMapper (line 39) | class SafeMapper(dict):
    method __missing__ (line 43) | def __missing__(cls, key):
  function report (line 48) | def report(manager, fileobj, sev_level, conf_level, template=None):

FILE: bandit/formatters/html.py
  function report (line 161) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/json.py
  function report (line 91) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/sarif.py
  function report (line 146) | def report(manager, fileobj, sev_level, conf_level, lines=-1):
  function add_skipped_file_notifications (line 201) | def add_skipped_file_notifications(skips, invocation):
  function add_results (line 228) | def add_results(issues, run):
  function create_result (line 242) | def create_result(issue, rules, rule_indices):
  function level_from_severity (line 274) | def level_from_severity(severity):
  function add_region_and_context_region (line 285) | def add_region_and_context_region(
  function parse_code (line 311) | def parse_code(code):
  function create_or_find_rule (line 342) | def create_or_find_rule(issue_dict, rules, rule_indices):
  function to_uri (line 366) | def to_uri(file_path):

FILE: bandit/formatters/screen.py
  function header (line 69) | def header(text, *args):
  function get_verbose_details (line 73) | def get_verbose_details(manager):
  function get_metrics (line 88) | def get_metrics(manager):
  function _output_issue_str (line 104) | def _output_issue_str(
  function get_results (line 152) | def get_results(manager, sev_level, conf_level, lines):
  function do_print (line 185) | def do_print(bits):
  function report (line 191) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/text.py
  function get_verbose_details (line 47) | def get_verbose_details(manager):
  function get_metrics (line 62) | def get_metrics(manager):
  function _output_issue_str (line 78) | def _output_issue_str(
  function get_results (line 118) | def get_results(manager, sev_level, conf_level, lines):
  function report (line 151) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/utils.py
  function wrap_file_object (line 8) | def wrap_file_object(fileobj):

FILE: bandit/formatters/xml.py
  function report (line 45) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/formatters/yaml.py
  function report (line 76) | def report(manager, fileobj, sev_level, conf_level, lines=-1):

FILE: bandit/plugins/app_debug.py
  function flask_debug_true (line 51) | def flask_debug_true(context):

FILE: bandit/plugins/asserts.py
  function gen_config (line 62) | def gen_config(name):
  function assert_used (line 70) | def assert_used(context, config):

FILE: bandit/plugins/crypto_request_no_cert_validation.py
  function request_with_no_cert_validation (line 56) | def request_with_no_cert_validation(context):

FILE: bandit/plugins/django_sql_injection.py
  function keywords2dict (line 12) | def keywords2dict(keywords):
  function django_extra_used (line 22) | def django_extra_used(context):
  function django_rawsql_used (line 111) | def django_rawsql_used(context):

FILE: bandit/plugins/django_xss.py
  class DeepAssignation (line 12) | class DeepAssignation:
    method __init__ (line 13) | def __init__(self, var_name, ignore_nodes=None):
    method is_assigned_in (line 17) | def is_assigned_in(self, items):
    method is_assigned (line 28) | def is_assigned(self, node):
  function evaluate_var (line 85) | def evaluate_var(xss_var, parent, until, ignore_nodes=None):
  function evaluate_call (line 132) | def evaluate_call(call, parent, ignore_nodes=None):
  function transform2call (line 172) | def transform2call(var):
  function check_risk (line 194) | def check_risk(node):
  function django_mark_safe (line 243) | def django_mark_safe(context):

FILE: bandit/plugins/exec.py
  function exec_issue (line 42) | def exec_issue():
  function exec_used (line 53) | def exec_used(context):

FILE: bandit/plugins/general_bad_file_permissions.py
  function _stat_is_dangerous (line 63) | def _stat_is_dangerous(mode):
  function set_bad_file_permissions (line 74) | def set_bad_file_permissions(context):

FILE: bandit/plugins/general_bind_all_interfaces.py
  function hardcoded_bind_all_interfaces (line 45) | def hardcoded_bind_all_interfaces(context):

FILE: bandit/plugins/general_hardcoded_password.py
  function _report (line 18) | def _report(value, lineno=None):
  function hardcoded_password_string (line 30) | def hardcoded_password_string(context):
  function hardcoded_password_funcarg (line 150) | def hardcoded_password_funcarg(context):
  function hardcoded_password_default (line 210) | def hardcoded_password_default(context):

FILE: bandit/plugins/general_hardcoded_tmp.py
  function gen_config (line 59) | def gen_config(name):
  function hardcoded_tmp_directory (line 67) | def hardcoded_tmp_directory(context, config):

FILE: bandit/plugins/hashlib_insecure_functions.py
  function _hashlib_func (line 56) | def _hashlib_func(context, func):
  function _crypt_crypt (line 84) | def _crypt_crypt(context, func):
  function hashlib (line 112) | def hashlib(context):

FILE: bandit/plugins/huggingface_unsafe_download.py
  function huggingface_unsafe_download (line 72) | def huggingface_unsafe_download(context):

FILE: bandit/plugins/injection_paramiko.py
  function paramiko_calls (line 50) | def paramiko_calls(context):

FILE: bandit/plugins/injection_shell.py
  function _evaluate_shell_call (line 17) | def _evaluate_shell_call(context):
  function gen_config (line 28) | def gen_config(name):
  function has_shell (line 81) | def has_shell(context):
  function subprocess_popen_with_shell_equals_true (line 110) | def subprocess_popen_with_shell_equals_true(context, config):
  function subprocess_without_shell_equals_true (line 237) | def subprocess_without_shell_equals_true(context, config):
  function any_other_function_with_shell_equals_true (line 323) | def any_other_function_with_shell_equals_true(context, config):
  function start_process_with_a_shell (line 408) | def start_process_with_a_shell(context, config):
  function start_process_with_no_shell (line 511) | def start_process_with_no_shell(context, config):
  function start_process_with_partial_path (line 605) | def start_process_with_partial_path(context, config):

FILE: bandit/plugins/injection_sql.py
  function _check_string (line 83) | def _check_string(data):
  function _evaluate_ast (line 87) | def _evaluate_ast(node):
  function hardcoded_sql_expressions (line 130) | def hardcoded_sql_expressions(context):

FILE: bandit/plugins/injection_wildcard.py
  function linux_commands_wildcard_injection (line 113) | def linux_commands_wildcard_injection(context, config):

FILE: bandit/plugins/insecure_ssl_tls.py
  function get_bad_proto_versions (line 10) | def get_bad_proto_versions(config):
  function gen_config (line 14) | def gen_config(name):
  function ssl_with_bad_version (line 34) | def ssl_with_bad_version(context, config):
  function ssl_with_bad_defaults (line 160) | def ssl_with_bad_defaults(context, config):
  function ssl_with_no_version (line 225) | def ssl_with_no_version(context):

FILE: bandit/plugins/jinja2_templates.py
  function jinja2_autoescape_false (line 75) | def jinja2_autoescape_false(context):

FILE: bandit/plugins/logging_config_insecure_listen.py
  function logging_config_insecure_listen (line 48) | def logging_config_insecure_listen(context):

FILE: bandit/plugins/mako_templates.py
  function use_of_mako_templates (line 52) | def use_of_mako_templates(context):

FILE: bandit/plugins/markupsafe_markup_xss.py
  function gen_config (line 79) | def gen_config(name):
  function markupsafe_markup_xss (line 90) | def markupsafe_markup_xss(context, config):

FILE: bandit/plugins/pytorch_load.py
  function pytorch_load (line 52) | def pytorch_load(context):

FILE: bandit/plugins/request_without_timeout.py
  function request_without_timeout (line 57) | def request_without_timeout(context):

FILE: bandit/plugins/snmp_security_check.py
  function snmp_insecure_version_check (line 12) | def snmp_insecure_version_check(context):
  function snmp_crypto_check (line 63) | def snmp_crypto_check(context):

FILE: bandit/plugins/ssh_no_host_key_verification.py
  function ssh_no_host_key_verification (line 47) | def ssh_no_host_key_verification(context):

FILE: bandit/plugins/tarfile_unsafe_members.py
  function exec_issue (line 56) | def exec_issue(level, members=""):
  function get_members_value (line 86) | def get_members_value(context):
  function is_filter_data (line 97) | def is_filter_data(context):
  function tarfile_unsafe_members (line 106) | def tarfile_unsafe_members(context):

FILE: bandit/plugins/trojansource.py
  function trojansource (line 56) | def trojansource(context):

FILE: bandit/plugins/try_except_continue.py
  function gen_config (line 84) | def gen_config(name):
  function try_except_continue (line 92) | def try_except_continue(context, config):

FILE: bandit/plugins/try_except_pass.py
  function gen_config (line 82) | def gen_config(name):
  function try_except_pass (line 90) | def try_except_pass(context, config):

FILE: bandit/plugins/weak_cryptographic_key.py
  function gen_config (line 47) | def gen_config(name):
  function _classify_key_size (line 59) | def _classify_key_size(config, key_type, key_size):
  function _weak_crypto_key_size_cryptography_io (line 90) | def _weak_crypto_key_size_cryptography_io(context, config):
  function _weak_crypto_key_size_pycrypto (line 142) | def _weak_crypto_key_size_pycrypto(context, config):
  function weak_cryptographic_key (line 162) | def weak_cryptographic_key(context, config):

FILE: bandit/plugins/yaml_load.py
  function yaml_load (line 51) | def yaml_load(context):

FILE: examples/eval.py
  class Test (line 9) | class Test(object):
    method eval (line 10) | def eval(self):
    method foo (line 12) | def foo(self):

FILE: examples/flask_debug.py
  function main (line 6) | def main():

FILE: examples/hardcoded-passwords.py
  class SomeClass (line 3) | class SomeClass:
  function someFunction (line 8) | def someFunction(user, password="Admin"):
  function someFunction2 (line 11) | def someFunction2(password):
  function noMatch (line 17) | def noMatch(password):
  function NoMatch2 (line 23) | def NoMatch2(password):
  function noMatchObject (line 29) | def noMatchObject():
  function doLogin (line 38) | def doLogin(password="blerg"):
  function NoMatch3 (line 41) | def NoMatch3(a, b):
  function __init__ (line 74) | def __init__(self, auth_scheme, auth_token=None, auth_username=None, aut...

FILE: examples/httpoxy_cgihandler.py
  function application (line 4) | def application(environ, start_response):

FILE: examples/jinja2_templating.py
  function fake_func (line 27) | def fake_func():

FILE: examples/mark_safe_insecure.py
  function insecure_function (line 5) | def insecure_function(text, cls=''):
  function try_insecure (line 17) | def try_insecure(cls='" onload="alert(\'xss\')'):
  function except_insecure (line 25) | def except_insecure(cls='" onload="alert(\'xss\')'):
  function try_else_insecure (line 33) | def try_else_insecure(cls='" onload="alert(\'xss\')'):
  function finally_insecure (line 44) | def finally_insecure(cls='" onload="alert(\'xss\')'):
  function format_arg_insecure (line 57) | def format_arg_insecure(cls='" onload="alert(\'xss\')'):
  function format_startarg_insecure (line 62) | def format_startarg_insecure(cls='" onload="alert(\'xss\')'):
  function format_keywords_insecure (line 67) | def format_keywords_insecure(cls='" onload="alert(\'xss\')'):
  function format_kwargs_insecure (line 72) | def format_kwargs_insecure(cls='" onload="alert(\'xss\')'):
  function percent_insecure (line 77) | def percent_insecure(cls='" onload="alert(\'xss\')'):
  function percent_list_insecure (line 82) | def percent_list_insecure(cls='" onload="alert(\'xss\')'):
  function percent_dict_insecure (line 87) | def percent_dict_insecure(cls='" onload="alert(\'xss\')'):
  function import_insecure (line 92) | def import_insecure():
  function import_as_insecure (line 97) | def import_as_insecure():
  function from_import_insecure (line 102) | def from_import_insecure():
  function from_import_as_insecure (line 107) | def from_import_as_insecure():
  function with_insecure (line 112) | def with_insecure(path):
  function also_with_insecure (line 117) | def also_with_insecure(path):
  function for_insecure (line 122) | def for_insecure():
  function while_insecure (line 129) | def while_insecure():
  function some_insecure_case (line 136) | def some_insecure_case():
  function test_insecure_shadow (line 148) | def test_insecure_shadow():  # var assigned out of scope
  function test_insecure (line 152) | def test_insecure(str_arg):
  function test_insecure_with_assign (line 156) | def test_insecure_with_assign(str_arg=None):
  function test_insecure_tuple_assign (line 161) | def test_insecure_tuple_assign():

FILE: examples/mark_safe_secure.py
  function try_secure (line 20) | def try_secure():
  function format_secure (line 32) | def format_secure():
  function percent_secure (line 44) | def percent_secure():
  function with_secure (line 52) | def with_secure(path):
  function loop_secure (line 57) | def loop_secure():
  function all_secure_case (line 68) | def all_secure_case():

FILE: examples/new_candidates-all.py
  function subprocess_shell_cmd (line 4) | def subprocess_shell_cmd():
  function yaml_load (line 11) | def yaml_load():
  function xml_sax_make_parser (line 19) | def xml_sax_make_parser():

FILE: examples/new_candidates-none.py
  function subprocess_shell_cmd (line 1) | def subprocess_shell_cmd():
  function yaml_load (line 4) | def yaml_load():
  function xml_sax_make_parser (line 7) | def xml_sax_make_parser():

FILE: examples/new_candidates-nosec.py
  function subprocess_shell_cmd (line 4) | def subprocess_shell_cmd():
  function yaml_load (line 9) | def yaml_load():
  function xml_sax_make_parser (line 15) | def xml_sax_make_parser():

FILE: examples/new_candidates-some.py
  function subprocess_shell_cmd (line 4) | def subprocess_shell_cmd():
  function yaml_load (line 11) | def yaml_load():
  function xml_sax_make_parser (line 17) | def xml_sax_make_parser():

FILE: examples/pycrypto.py
  function test_pycrypto (line 7) | def test_pycrypto():

FILE: examples/pycryptodome.py
  function test_pycrypto (line 7) | def test_pycrypto():

FILE: examples/sql_multiline_statements.py
  function a (line 115) | def a():

FILE: examples/sql_statements.py
  function a (line 42) | def a():

FILE: examples/ssl-insecure-version.py
  function open_ssl_socket (line 32) | def open_ssl_socket(version=ssl.PROTOCOL_SSLv2):
  function open_ssl_socket (line 35) | def open_ssl_socket(version=SSL.SSLv2_METHOD):
  function open_ssl_socket (line 38) | def open_ssl_socket(version=SSL.SSLv23_METHOD):
  function open_ssl_socket (line 41) | def open_ssl_socket(version=SSL.TLSv1_1_METHOD):
  function open_ssl_socket (line 45) | def open_ssl_socket(version=SSL.TLSv1_2_METHOD):

FILE: examples/subprocess_shell.py
  function Popen (line 5) | def Popen(*args, **kwargs):

FILE: examples/tarfile_extractall.py
  function unsafe_archive_handler (line 6) | def unsafe_archive_handler(filename):
  function managed_members_archive_handler (line 12) | def managed_members_archive_handler(filename):
  function filter_data_archive_handler (line 18) | def filter_data_archive_handler(filename):
  function filter_fully_trusted_archive_handler (line 24) | def filter_fully_trusted_archive_handler(filename):
  function list_members_archive_handler (line 30) | def list_members_archive_handler(filename):
  function provided_members_archive_handler (line 36) | def provided_members_archive_handler(filename):
  function members_filter (line 42) | def members_filter(tarfile):

FILE: examples/urlopen.py
  function test_urlopen (line 15) | def test_urlopen():

FILE: examples/xml_sax.py
  class ExampleContentHandler (line 5) | class ExampleContentHandler(xml.sax.ContentHandler):
    method __init__ (line 6) | def __init__(self):
    method startElement (line 9) | def startElement(self, name, attrs):
    method endElement (line 12) | def endElement(self, name):
    method characters (line 15) | def characters(self, content):
  function main (line 18) | def main():

FILE: examples/xml_xmlrpc.py
  function is_even (line 4) | def is_even(n):

FILE: examples/yaml_load.py
  function test_yaml_load (line 7) | def test_yaml_load():
  function test_json_load (line 18) | def test_json_load():

FILE: tests/functional/test_baseline.py
  class BaselineFunctionalTests (line 28) | class BaselineFunctionalTests(testtools.TestCase):
    method setUp (line 38) | def setUp(self):
    method _run_bandit_baseline (line 44) | def _run_bandit_baseline(self, target_directory, baseline_file):
    method _create_baseline (line 65) | def _create_baseline(self, baseline_paired_files):
    method test_no_new_candidates (line 115) | def test_no_new_candidates(self):
    method test_no_existing_no_new_candidates (line 142) | def test_no_existing_no_new_candidates(self):
    method test_no_existing_with_new_candidates (line 167) | def test_no_existing_with_new_candidates(self):
    method test_existing_and_new_candidates (line 202) | def test_existing_and_new_candidates(self):
    method test_no_new_candidates_include_nosec (line 234) | def test_no_new_candidates_include_nosec(self):
    method test_new_candidates_include_nosec_only_nosecs (line 263) | def test_new_candidates_include_nosec_only_nosecs(self):
    method test_new_candidates_include_nosec_new_nosecs (line 300) | def test_new_candidates_include_nosec_new_nosecs(self):

FILE: tests/functional/test_functional.py
  class FunctionalTests (line 17) | class FunctionalTests(testtools.TestCase):
    method setUp (line 26) | def setUp(self):
    method with_test_set (line 38) | def with_test_set(self, ts):
    method run_example (line 49) | def run_example(self, example_script, ignore_nosec=False):
    method check_example (line 62) | def check_example(self, example_script, expect, ignore_nosec=False):
    method check_metrics (line 87) | def check_metrics(self, example_script, expect):
    method test_binding (line 112) | def test_binding(self):
    method test_crypto_md5 (line 120) | def test_crypto_md5(self):
    method test_ciphers (line 128) | def test_ciphers(self):
    method test_cipher_modes (line 136) | def test_cipher_modes(self):
    method test_eval (line 144) | def test_eval(self):
    method test_mark_safe (line 152) | def test_mark_safe(self):
    method test_exec (line 160) | def test_exec(self):
    method test_hardcoded_passwords (line 168) | def test_hardcoded_passwords(self):
    method test_hardcoded_tmp (line 176) | def test_hardcoded_tmp(self):
    method test_imports_aliases (line 184) | def test_imports_aliases(self):
    method test_imports_from (line 192) | def test_imports_from(self):
    method test_imports_function (line 200) | def test_imports_function(self):
    method test_telnet_usage (line 208) | def test_telnet_usage(self):
    method test_ftp_usage (line 216) | def test_ftp_usage(self):
    method test_imports (line 224) | def test_imports(self):
    method test_imports_using_importlib (line 232) | def test_imports_using_importlib(self):
    method test_mktemp (line 240) | def test_mktemp(self):
    method test_nonsense (line 248) | def test_nonsense(self):
    method test_okay (line 253) | def test_okay(self):
    method test_subdirectory_okay (line 261) | def test_subdirectory_okay(self):
    method test_os_chmod (line 269) | def test_os_chmod(self):
    method test_os_exec (line 277) | def test_os_exec(self):
    method test_os_popen (line 285) | def test_os_popen(self):
    method test_os_spawn (line 293) | def test_os_spawn(self):
    method test_os_startfile (line 301) | def test_os_startfile(self):
    method test_os_system (line 309) | def test_os_system(self):
    method test_pickle (line 317) | def test_pickle(self):
    method test_dill (line 325) | def test_dill(self):
    method test_shelve (line 333) | def test_shelve(self):
    method test_jsonpickle (line 341) | def test_jsonpickle(self):
    method test_pandas_read_pickle (line 349) | def test_pandas_read_pickle(self):
    method test_popen_wrappers (line 357) | def test_popen_wrappers(self):
    method test_random_module (line 365) | def test_random_module(self):
    method test_requests_ssl_verify_disabled (line 373) | def test_requests_ssl_verify_disabled(self):
    method test_requests_without_timeout (line 381) | def test_requests_without_timeout(self):
    method test_skip (line 389) | def test_skip(self):
    method test_ignore_skip (line 397) | def test_ignore_skip(self):
    method test_sql_statements (line 405) | def test_sql_statements(self):
    method test_multiline_sql_statements (line 423) | def test_multiline_sql_statements(self):
    method test_ssl_insecure_version (line 454) | def test_ssl_insecure_version(self):
    method test_subprocess_shell (line 462) | def test_subprocess_shell(self):
    method test_urlopen (line 470) | def test_urlopen(self):
    method test_wildcard_injection (line 478) | def test_wildcard_injection(self):
    method test_django_sql_injection (line 486) | def test_django_sql_injection(self):
    method test_django_sql_injection_raw (line 495) | def test_django_sql_injection_raw(self):
    method test_yaml (line 504) | def test_yaml(self):
    method test_host_key_verification (line 512) | def test_host_key_verification(self):
    method test_jinja2_templating (line 520) | def test_jinja2_templating(self):
    method test_mako_templating (line 528) | def test_mako_templating(self):
    method test_django_xss_secure (line 536) | def test_django_xss_secure(self):
    method test_django_xss_insecure (line 549) | def test_django_xss_insecure(self):
    method test_xml (line 562) | def test_xml(self):
    method test_httpoxy (line 612) | def test_httpoxy(self):
    method test_asserts (line 622) | def test_asserts(self):
    method test_paramiko_injection (line 651) | def test_paramiko_injection(self):
    method test_partial_path (line 659) | def test_partial_path(self):
    method test_try_except_continue (line 667) | def test_try_except_continue(self):
    method test_try_except_pass (line 689) | def test_try_except_pass(self):
    method test_metric_gathering (line 711) | def test_metric_gathering(self):
    method test_weak_cryptographic_key (line 725) | def test_weak_cryptographic_key(self):
    method test_multiline_code (line 733) | def test_multiline_code(self):
    method test_code_line_numbers (line 757) | def test_code_line_numbers(self):
    method test_flask_debug_true (line 767) | def test_flask_debug_true(self):
    method test_nosec (line 774) | def test_nosec(self):
    method test_baseline_filter (line 781) | def test_baseline_filter(self):
    method test_unverified_context (line 816) | def test_unverified_context(self):
    method test_hashlib_new_insecure_functions (line 824) | def test_hashlib_new_insecure_functions(self):
    method test_blacklist_pycrypto (line 832) | def test_blacklist_pycrypto(self):
    method test_no_blacklist_pycryptodome (line 840) | def test_no_blacklist_pycryptodome(self):
    method test_blacklist_pyghmi (line 851) | def test_blacklist_pyghmi(self):
    method test_snmp_security_check (line 859) | def test_snmp_security_check(self):
    method test_tarfile_unsafe_members (line 867) | def test_tarfile_unsafe_members(self):
    method test_pytorch_load (line 875) | def test_pytorch_load(self):
    method test_trojansource (line 883) | def test_trojansource(self):
    method test_trojansource_latin1 (line 890) | def test_trojansource_latin1(self):
    method test_markupsafe_markup_xss (line 897) | def test_markupsafe_markup_xss(self):
    method test_markupsafe_markup_xss_extend_markup_names (line 904) | def test_markupsafe_markup_xss_extend_markup_names(self):
    method test_markupsafe_markup_xss_allowed_calls (line 918) | def test_markupsafe_markup_xss_allowed_calls(self):
    method test_huggingface_unsafe_download (line 930) | def test_huggingface_unsafe_download(self):

FILE: tests/functional/test_runtime.py
  class RuntimeTests (line 10) | class RuntimeTests(testtools.TestCase):
    method _test_runtime (line 11) | def _test_runtime(self, cmdlist, infile=None):
    method _test_example (line 23) | def _test_example(self, cmdlist, targets):
    method test_no_arguments (line 28) | def test_no_arguments(self):
    method test_piped_input (line 37) | def test_piped_input(self):
    method test_nonexistent_config (line 49) | def test_nonexistent_config(self):
    method test_help_arg (line 56) | def test_help_arg(self):
    method test_example_nonexistent (line 67) | def test_example_nonexistent(self):
    method test_example_okay (line 80) | def test_example_okay(self):
    method test_example_nonsense (line 94) | def test_example_nonsense(self):
    method test_example_nonsense2 (line 107) | def test_example_nonsense2(self):
    method test_example_imports (line 120) | def test_example_imports(self):

FILE: tests/unit/cli/test_baseline.py
  class BanditBaselineToolTests (line 33) | class BanditBaselineToolTests(testtools.TestCase):
    method setUpClass (line 35) | def setUpClass(cls):
    method setUp (line 41) | def setUp(self):
    method tearDown (line 46) | def tearDown(self):
    method test_bandit_baseline (line 51) | def test_bandit_baseline(self):
    method test_main_non_repo (line 124) | def test_main_non_repo(self):
    method test_main_git_command_failure (line 133) | def test_main_git_command_failure(self):
    method test_main_no_parent_commit (line 154) | def test_main_no_parent_commit(self):
    method test_main_subprocess_error (line 166) | def test_main_subprocess_error(self):
    method test_init_logger (line 191) | def test_init_logger(self):
    method test_initialize_no_repo (line 199) | def test_initialize_no_repo(self):
    method test_initialize_git_command_failure (line 210) | def test_initialize_git_command_failure(self):
    method test_initialize_dirty_repo (line 231) | def test_initialize_dirty_repo(self):
    method test_initialize_existing_report_file (line 250) | def test_initialize_existing_report_file(self):
    method test_initialize_with_output_argument (line 272) | def test_initialize_with_output_argument(self):
    method test_initialize_existing_temp_file (line 285) | def test_initialize_existing_temp_file(self):

FILE: tests/unit/cli/test_config_generator.py
  function gen_config (line 17) | def gen_config(name):
  function _test_plugin (line 23) | def _test_plugin(context, conf):
  class BanditConfigGeneratorLoggerTests (line 27) | class BanditConfigGeneratorLoggerTests(testtools.TestCase):
    method setUp (line 28) | def setUp(self):
    method tearDown (line 35) | def tearDown(self):
    method test_init_logger (line 40) | def test_init_logger(self):
  class BanditConfigGeneratorTests (line 48) | class BanditConfigGeneratorTests(testtools.TestCase):
    method test_parse_args_no_defaults (line 50) | def test_parse_args_no_defaults(self):
    method test_parse_args_show_defaults (line 55) | def test_parse_args_show_defaults(self):
    method test_parse_args_out_file (line 61) | def test_parse_args_out_file(self):
    method test_get_config_settings (line 66) | def test_get_config_settings(self):
    method test_main_show_defaults (line 79) | def test_main_show_defaults(self):

FILE: tests/unit/cli/test_main.py
  class BanditCLIMainLoggerTests (line 50) | class BanditCLIMainLoggerTests(testtools.TestCase):
    method setUp (line 51) | def setUp(self):
    method tearDown (line 58) | def tearDown(self):
    method test_init_logger (line 63) | def test_init_logger(self):
    method test_init_logger_debug_mode (line 71) | def test_init_logger_debug_mode(self):
  class BanditCLIMainTests (line 77) | class BanditCLIMainTests(testtools.TestCase):
    method setUp (line 78) | def setUp(self):
    method tearDown (line 82) | def tearDown(self):
    method test_get_options_from_ini_no_ini_path_no_target (line 86) | def test_get_options_from_ini_no_ini_path_no_target(self):
    method test_get_options_from_ini_empty_directory_no_target (line 91) | def test_get_options_from_ini_empty_directory_no_target(self):
    method test_get_options_from_ini_no_ini_path_no_bandit_files (line 97) | def test_get_options_from_ini_no_ini_path_no_bandit_files(self):
    method test_get_options_from_ini_no_ini_path_multi_bandit_files (line 105) | def test_get_options_from_ini_no_ini_path_multi_bandit_files(self):
    method test_init_extensions (line 127) | def test_init_extensions(self):
    method test_log_option_source_arg_val (line 131) | def test_log_option_source_arg_val(self):
    method test_log_option_source_ini_value (line 145) | def test_log_option_source_ini_value(self):
    method test_log_option_source_ini_val_with_str_default_and_no_arg_val (line 156) | def test_log_option_source_ini_val_with_str_default_and_no_arg_val(self):
    method test_log_option_source_no_values (line 170) | def test_log_option_source_no_values(self):
    method test_main_config_unopenable (line 179) | def test_main_config_unopenable(self):
    method test_main_invalid_config (line 187) | def test_main_invalid_config(self):
    method test_main_handle_ini_options (line 198) | def test_main_handle_ini_options(self):
    method test_main_profile_not_found (line 224) | def test_main_profile_not_found(self):
    method test_main_baseline_ioerror (line 241) | def test_main_baseline_ioerror(self):
    method test_main_invalid_output_format (line 270) | def test_main_invalid_output_format(self):
    method test_main_exit_with_results (line 284) | def test_main_exit_with_results(self):
    method test_main_exit_with_no_results (line 300) | def test_main_exit_with_no_results(self):
    method test_main_exit_with_results_and_with_exit_zero_flag (line 317) | def test_main_exit_with_results_and_with_exit_zero_flag(self):

FILE: tests/unit/core/test_blacklisting.py
  class BlacklistingTests (line 10) | class BlacklistingTests(testtools.TestCase):
    method test_report_issue (line 11) | def test_report_issue(self):
    method test_report_issue_defaults (line 23) | def test_report_issue_defaults(self):

FILE: tests/unit/core/test_config.py
  class TempFile (line 17) | class TempFile(fixtures.Fixture):
    method __init__ (line 18) | def __init__(self, contents=None, suffix=".yaml"):
    method setUp (line 23) | def setUp(self):
  class TestInit (line 37) | class TestInit(testtools.TestCase):
    method test_settings (line 38) | def test_settings(self):
    method test_file_does_not_exist (line 53) | def test_file_does_not_exist(self):
    method test_yaml_invalid (line 61) | def test_yaml_invalid(self):
  class TestGetOption (line 73) | class TestGetOption(testtools.TestCase):
    method setUp (line 74) | def setUp(self):
    method test_levels (line 91) | def test_levels(self):
    method test_levels_not_exist (line 99) | def test_levels_not_exist(self):
  class TestGetSetting (line 106) | class TestGetSetting(testtools.TestCase):
    method setUp (line 107) | def setUp(self):
    method test_not_exist (line 113) | def test_not_exist(self):
  class TestConfigCompat (line 120) | class TestConfigCompat(testtools.TestCase):
    method setUp (line 170) | def setUp(self):
    method test_converted_include (line 175) | def test_converted_include(self):
    method test_converted_exclude (line 186) | def test_converted_exclude(self):
    method test_converted_blacklist_call_data (line 192) | def test_converted_blacklist_call_data(self):
    method test_converted_blacklist_import_data (line 208) | def test_converted_blacklist_import_data(self):
    method test_converted_blacklist_call_test (line 223) | def test_converted_blacklist_call_test(self):
    method test_converted_blacklist_import_test (line 229) | def test_converted_blacklist_import_test(self):
    method test_converted_exclude_blacklist (line 235) | def test_converted_exclude_blacklist(self):
    method test_deprecation_message (line 241) | def test_deprecation_message(self):
    method test_blacklist_error (line 254) | def test_blacklist_error(self):
    method test_bad_yaml (line 274) | def test_bad_yaml(self):
  class TestTomlConfig (line 282) | class TestTomlConfig(TestConfigCompat):

FILE: tests/unit/core/test_context.py
  class ContextTests (line 13) | class ContextTests(testtools.TestCase):
    method test_context_create (line 14) | def test_context_create(self):
    method test_repr (line 22) | def test_repr(self):
    method test_call_args (line 29) | def test_call_args(self, get_literal_value):
    method test_call_args_count (line 38) | def test_call_args_count(self):
    method test_call_function_name (line 52) | def test_call_function_name(self):
    method test_call_function_name_qual (line 61) | def test_call_function_name_qual(self):
    method test_call_keywords (line 71) | def test_call_keywords(self, get_literal_value):
    method test_node (line 89) | def test_node(self):
    method test_string_val (line 98) | def test_string_val(self):
    method test_statement (line 107) | def test_statement(self):
    method test_function_def_defaults_qual (line 117) | def test_function_def_defaults_qual(self, get_qual_attr):
    method test__get_literal_value (line 132) | def test__get_literal_value(self):
    method test_check_call_arg_value (line 173) | def test_check_call_arg_value(self, call_keywords):
    method test_get_lineno_for_call_arg (line 190) | def test_get_lineno_for_call_arg(self, node):
    method test_get_call_arg_at_position (line 204) | def test_get_call_arg_at_position(self):
    method test_is_module_being_imported (line 222) | def test_is_module_being_imported(self):
    method test_is_module_imported_exact (line 231) | def test_is_module_imported_exact(self):
    method test_is_module_imported_like (line 240) | def test_is_module_imported_like(self):
    method test_filename (line 249) | def test_filename(self):

FILE: tests/unit/core/test_docs_util.py
  class DocsUtilTests (line 10) | class DocsUtilTests(testtools.TestCase):
    method test_overwrite_bib_info (line 15) | def test_overwrite_bib_info(self):
    method test_plugin_call_bib (line 22) | def test_plugin_call_bib(self):
    method test_import_call_bib (line 26) | def test_import_call_bib(self):

FILE: tests/unit/core/test_issue.py
  class IssueTests (line 14) | class IssueTests(testtools.TestCase):
    method test_issue_create (line 15) | def test_issue_create(self):
    method test_issue_str (line 19) | def test_issue_str(self):
    method test_issue_as_dict (line 32) | def test_issue_as_dict(self):
    method test_issue_filter_severity (line 54) | def test_issue_filter_severity(self):
    method test_issue_filter_confidence (line 65) | def test_issue_filter_confidence(self):
    method test_matches_issue (line 76) | def test_matches_issue(self):
    method test_get_code (line 121) | def test_get_code(self, getline):
  function _get_issue_instance (line 133) | def _get_issue_instance(

FILE: tests/unit/core/test_manager.py
  class ManagerTests (line 17) | class ManagerTests(testtools.TestCase):
    method _get_issue_instance (line 18) | def _get_issue_instance(
    method setUp (line 30) | def setUp(self):
    method test_create_manager (line 43) | def test_create_manager(self):
    method test_create_manager_with_profile (line 49) | def test_create_manager_with_profile(self):
    method test_matches_globlist (line 63) | def test_matches_globlist(self):
    method test_is_file_included (line 67) | def test_is_file_included(self):
    method test_get_files_from_dir (line 117) | def test_get_files_from_dir(self, os_walk):
    method test_populate_baseline_success (line 130) | def test_populate_baseline_success(self):
    method test_populate_baseline_invalid_json (line 171) | def test_populate_baseline_invalid_json(self, mock_logger_warning):
    method test_results_count (line 179) | def test_results_count(self):
    method test_output_results_invalid_format (line 195) | def test_output_results_invalid_format(self):
    method test_output_results_valid_format (line 209) | def test_output_results_valid_format(self):
    method test_discover_files_recurse_skip (line 224) | def test_discover_files_recurse_skip(self, isdir):
    method test_discover_files_recurse_files (line 231) | def test_discover_files_recurse_files(self, isdir):
    method test_discover_files_exclude (line 240) | def test_discover_files_exclude(self, isdir):
    method test_discover_files_exclude_dir (line 249) | def test_discover_files_exclude_dir(self, isdir):
    method test_discover_files_exclude_cmdline (line 276) | def test_discover_files_exclude_cmdline(self, isdir):
    method test_discover_files_exclude_glob (line 287) | def test_discover_files_exclude_glob(self, isdir):
    method test_discover_files_include (line 296) | def test_discover_files_include(self, isdir):
    method test_run_tests_keyboardinterrupt (line 304) | def test_run_tests_keyboardinterrupt(self):
    method test_run_tests_ioerror (line 318) | def test_run_tests_ioerror(self):
    method test_compare_baseline (line 330) | def test_compare_baseline(self):
    method test_find_candidate_matches (line 364) | def test_find_candidate_matches(self):

FILE: tests/unit/core/test_meta_ast.py
  class BanditMetaAstTests (line 9) | class BanditMetaAstTests(testtools.TestCase):
    method setUp (line 10) | def setUp(self):
    method test_add_node (line 19) | def test_add_node(self):
    method test_str (line 27) | def test_str(self):

FILE: tests/unit/core/test_test_set.py
  function test_plugin (line 19) | def test_plugin():
  class BanditTestSetTests (line 46) | class BanditTestSetTests(testtools.TestCase):
    method _make_test_manager (line 47) | def _make_test_manager(self, plugin):
    method setUp (line 52) | def setUp(self):
    method tearDown (line 63) | def tearDown(self):
    method test_has_defaults (line 68) | def test_has_defaults(self):
    method test_profile_include_id (line 72) | def test_profile_include_id(self):
    method test_profile_exclude_id (line 77) | def test_profile_exclude_id(self):
    method test_profile_include_none (line 82) | def test_profile_include_none(self):
    method test_profile_exclude_none (line 87) | def test_profile_exclude_none(self):
    method test_profile_has_builtin_blacklist (line 92) | def test_profile_has_builtin_blacklist(self):
    method test_profile_exclude_builtin_blacklist (line 98) | def test_profile_exclude_builtin_blacklist(self):
    method test_profile_exclude_builtin_blacklist_specific (line 105) | def test_profile_exclude_builtin_blacklist_specific(self):
    method test_profile_filter_blacklist_none (line 112) | def test_profile_filter_blacklist_none(self):
    method test_profile_filter_blacklist_one (line 120) | def test_profile_filter_blacklist_one(self):
    method test_profile_filter_blacklist_include (line 129) | def test_profile_filter_blacklist_include(self):
    method test_profile_filter_blacklist_all (line 138) | def test_profile_filter_blacklist_all(self):
    method test_profile_blacklist_compat (line 148) | def test_profile_blacklist_compat(self):

FILE: tests/unit/core/test_util.py
  function _touch (line 17) | def _touch(path):
  class UtilTests (line 22) | class UtilTests(testtools.TestCase):
    method setUp (line 25) | def setUp(self):
    method _setup_get_module_qualname_from_path (line 29) | def _setup_get_module_qualname_from_path(self):
    method test_get_module_qualname_from_path_abs_typical (line 100) | def test_get_module_qualname_from_path_abs_typical(self):
    method test_get_module_qualname_from_path_with_dot (line 110) | def test_get_module_qualname_from_path_with_dot(self):
    method test_get_module_qualname_from_path_abs_missingmid (line 119) | def test_get_module_qualname_from_path_abs_missingmid(self):
    method test_get_module_qualname_from_path_abs_missingend (line 130) | def test_get_module_qualname_from_path_abs_missingend(self):
    method test_get_module_qualname_from_path_abs_syms (line 141) | def test_get_module_qualname_from_path_abs_syms(self):
    method test_get_module_qualname_from_path_rel_typical (line 151) | def test_get_module_qualname_from_path_rel_typical(self):
    method test_get_module_qualname_from_path_rel_missingmid (line 161) | def test_get_module_qualname_from_path_rel_missingmid(self):
    method test_get_module_qualname_from_path_rel_missingend (line 177) | def test_get_module_qualname_from_path_rel_missingend(self):
    method test_get_module_qualname_from_path_rel_syms (line 193) | def test_get_module_qualname_from_path_rel_syms(self):
    method test_get_module_qualname_from_path_sys (line 202) | def test_get_module_qualname_from_path_sys(self):
    method test_get_module_qualname_from_path_invalid_path (line 212) | def test_get_module_qualname_from_path_invalid_path(self):
    method test_get_module_qualname_from_path_dir (line 218) | def test_get_module_qualname_from_path_dir(self):
    method test_namespace_path_join (line 227) | def test_namespace_path_join(self):
    method test_namespace_path_split (line 231) | def test_namespace_path_split(self):
    method test_get_call_name1 (line 236) | def test_get_call_name1(self):
    method test_get_call_name2 (line 242) | def test_get_call_name2(self):
    method test_get_call_name3 (line 255) | def test_get_call_name3(self):
    method test_linerange (line 263) | def test_linerange(self):
    method test_path_for_function (line 276) | def test_path_for_function(self):
    method test_path_for_function_no_file (line 280) | def test_path_for_function_no_file(self):
    method test_path_for_function_no_module (line 283) | def test_path_for_function_no_module(self):
    method test_escaped_representation_simple (line 286) | def test_escaped_representation_simple(self):
    method test_escaped_representation_valid_not_printable (line 290) | def test_escaped_representation_valid_not_printable(self):
    method test_escaped_representation_invalid (line 294) | def test_escaped_representation_invalid(self):
    method test_escaped_representation_mixed (line 298) | def test_escaped_representation_mixed(self):
    method test_deepgetattr (line 302) | def test_deepgetattr(self):
    method test_parse_ini_file (line 316) | def test_parse_ini_file(self):
    method test_check_ast_node_good (line 334) | def test_check_ast_node_good(self):
    method test_check_ast_node_bad_node (line 338) | def test_check_ast_node_bad_node(self):
    method test_check_ast_node_bad_type (line 341) | def test_check_ast_node_bad_type(self):

FILE: tests/unit/formatters/test_csv.py
  class CsvFormatterTests (line 16) | class CsvFormatterTests(testtools.TestCase):
    method setUp (line 17) | def setUp(self):
    method test_report (line 47) | def test_report(self):

FILE: tests/unit/formatters/test_custom.py
  class CustomFormatterTests (line 14) | class CustomFormatterTests(testtools.TestCase):
    method setUp (line 15) | def setUp(self):
    method test_report (line 44) | def test_report(self):

FILE: tests/unit/formatters/test_html.py
  class HtmlFormatterTests (line 19) | class HtmlFormatterTests(testtools.TestCase):
    method setUp (line 20) | def setUp(self):
    method test_report_with_skipped (line 29) | def test_report_with_skipped(self):
    method test_report_contents (line 45) | def test_report_contents(self, get_issue_list, get_code):
    method test_escaping (line 134) | def test_escaping(self, get_issue_list, get_code):
  function _get_issue_instance (line 152) | def _get_issue_instance(

FILE: tests/unit/formatters/test_json.py
  class JsonFormatterTests (line 20) | class JsonFormatterTests(testtools.TestCase):
    method setUp (line 21) | def setUp(self):
    method test_report (line 74) | def test_report(self, get_issue_list):

FILE: tests/unit/formatters/test_sarif.py
  class SarifFormatterTests (line 18) | class SarifFormatterTests(testtools.TestCase):
    method setUp (line 19) | def setUp(self):
    method test_report (line 79) | def test_report(self, get_issue_list):

FILE: tests/unit/formatters/test_screen.py
  class ScreenFormatterTests (line 19) | class ScreenFormatterTests(testtools.TestCase):
    method setUp (line 20) | def setUp(self):
    method test_output_issue (line 24) | def test_output_issue(self, get_code):
    method test_no_issues (line 83) | def test_no_issues(self, get_issue_list):
    method test_report_nobaseline (line 102) | def test_report_nobaseline(self, get_issue_list):
    method test_report_baseline (line 195) | def test_report_baseline(self, get_issue_list):
  function _get_issue_instance (line 237) | def _get_issue_instance(

FILE: tests/unit/formatters/test_text.py
  class TextFormatterTests (line 19) | class TextFormatterTests(testtools.TestCase):
    method setUp (line 20) | def setUp(self):
    method test_output_issue (line 24) | def test_output_issue(self, get_code):
    method test_no_issues (line 69) | def test_no_issues(self, get_issue_list):
    method test_report_nobaseline (line 87) | def test_report_nobaseline(self, get_issue_list):
    method test_report_baseline (line 170) | def test_report_baseline(self, get_issue_list):
  function _get_issue_instance (line 212) | def _get_issue_instance(

FILE: tests/unit/formatters/test_xml.py
  class XmlFormatterTests (line 17) | class XmlFormatterTests(testtools.TestCase):
    method setUp (line 18) | def setUp(self):
    method _xml_to_dict (line 44) | def _xml_to_dict(self, t):
    method test_report (line 64) | def test_report(self):

FILE: tests/unit/formatters/test_yaml.py
  class YamlFormatterTests (line 20) | class YamlFormatterTests(testtools.TestCase):
    method setUp (line 21) | def setUp(self):
    method test_report (line 62) | def test_report(self, get_issue_list):
Condensed preview — 291 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (856K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 41,
    "preview": "*       @ericwb @lukehinds @sigmavirus24\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 116,
    "preview": "custom: [\"https://psfmember.org/civicrm/contribute/transact/?reset=1&id=42\"]\ngithub: [ericwb]\ntidelift: pypi/bandit\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "chars": 698,
    "preview": "---\nname: \"\\U0001F680 Feature request\"\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "chars": 1799,
    "preview": "name: 🐛 Bug report\ndescription: Create a report to help us improve\nlabels: bug\n\nbody:\n  - type: markdown\n    attributes:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 172,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: ❓ Ask a question\n    url: https://github.com/PyCQA/bandit/discussio"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 119,
    "preview": "version: 2\nupdates:\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/build-publish-image.yml",
    "chars": 2119,
    "preview": "name: Build and Publish Bandit Images\n\non:\n  release:\n    types: [created]\n  schedule:\n    - cron: '0 0 * * 0' # Every S"
  },
  {
    "path": ".github/workflows/dependency-review.yml",
    "chars": 294,
    "preview": "name: 'Dependency Review'\non: [pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  dependency-review:\n    runs-on: ubu"
  },
  {
    "path": ".github/workflows/publish-to-pypi.yml",
    "chars": 893,
    "preview": "name: Publish to PyPI\n\non: workflow_dispatch\n\njobs:\n  build-n-publish:\n    name: Build and publish to PyPI\n    runs-on: "
  },
  {
    "path": ".github/workflows/publish-to-test-pypi.yml",
    "chars": 928,
    "preview": "name: Publish to Test PyPI\n\non: workflow_dispatch\n\njobs:\n  build-n-publish:\n    name: Build and publish to Test PyPI\n   "
  },
  {
    "path": ".github/workflows/pythonpackage.yml",
    "chars": 1846,
    "preview": "name: Build and Test Bandit\n\non: [push, pull_request]\n\njobs:\n  format:\n    runs-on: ubuntu-latest\n    strategy:\n      ma"
  },
  {
    "path": ".gitignore",
    "chars": 175,
    "preview": "env*\nvenv*\n.python-version\n*.pyc\n.DS_Store\n*.egg\n*.egg-info\n.eggs/\n.idea/\n.vscode/\n.tox\n.stestr\nbuild/*\ncover/*\n.coverag"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 879,
    "preview": "exclude: ^(examples|tools|doc)\nrepos:\n- repo: https://github.com/pre-commit/pre-commit-hooks\n  rev: v6.0.0\n  hooks:\n  - "
  },
  {
    "path": ".pre-commit-hooks.yaml",
    "chars": 232,
    "preview": "-   id: bandit\n    name: bandit\n    description: 'Bandit is a tool for finding common security issues in Python code'\n  "
  },
  {
    "path": ".readthedocs.yaml",
    "chars": 288,
    "preview": "version: 2\n\nbuild:\n  os: ubuntu-lts-latest\n  tools:\n    python: \"3.10\"\n\nsphinx:\n  configuration: doc/source/conf.py\n\npyt"
  },
  {
    "path": ".stestr.conf",
    "chars": 59,
    "preview": "[DEFAULT]\ntest_path=./tests\ntop_dir=./\nparallel_class=True\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5325,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 10798,
    "preview": "# Contributing to Bandit\nThanks for considering to take part in the improvement of the Bandit project. Contributions are"
  },
  {
    "path": "LICENSE",
    "chars": 10142,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.rst",
    "chars": 4516,
    "preview": ".. image:: https://raw.githubusercontent.com/pycqa/bandit/main/logo/logotype-sm.png\n    :alt: Bandit\n\n======\n\n.. image::"
  },
  {
    "path": "SECURITY.md",
    "chars": 609,
    "preview": "# Security Policy\n\nBandit is a tool designed to find security issues, so every effort is made that Bandit itself is also"
  },
  {
    "path": "bandit/__init__.py",
    "chars": 683,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nfrom importlib impo"
  },
  {
    "path": "bandit/__main__.py",
    "chars": 571,
    "preview": "#!/usr/bin/env python\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"Bandit is a tool designed to find common security issues "
  },
  {
    "path": "bandit/blacklists/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bandit/blacklists/calls.py",
    "chars": 29363,
    "preview": "#\n# Copyright 2016 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/blacklists/imports.py",
    "chars": 17269,
    "preview": "#\n# Copyright 2016 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/blacklists/utils.py",
    "chars": 420,
    "preview": "#\n# Copyright 2016 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"Utils module.\"\""
  },
  {
    "path": "bandit/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bandit/cli/baseline.py",
    "chars": 7841,
    "preview": "#\n# Copyright 2015 Hewlett-Packard Enterprise\n#\n# SPDX-License-Identifier: Apache-2.0\n# ################################"
  },
  {
    "path": "bandit/cli/config_generator.py",
    "chars": 6281,
    "preview": "# Copyright 2015 Red Hat Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"Bandit is a tool designed to find common securi"
  },
  {
    "path": "bandit/cli/main.py",
    "chars": 20876,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"Bandit is a tool"
  },
  {
    "path": "bandit/core/__init__.py",
    "chars": 558,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nfrom bandit.core im"
  },
  {
    "path": "bandit/core/blacklisting.py",
    "chars": 2780,
    "preview": "#\n# Copyright 2016 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\n\nfrom ba"
  },
  {
    "path": "bandit/core/config.py",
    "chars": 9840,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport logging\nimpo"
  },
  {
    "path": "bandit/core/constants.py",
    "chars": 1220,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\n# default plugin na"
  },
  {
    "path": "bandit/core/context.py",
    "chars": 10667,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\n\nfrom ba"
  },
  {
    "path": "bandit/core/docs_utils.py",
    "chars": 1779,
    "preview": "#\n# Copyright 2016 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport bandit\n\n\ndef"
  },
  {
    "path": "bandit/core/extension_loader.py",
    "chars": 4039,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nimport logging\nimport sys\n\nfrom stevedore import extension\n\nfrom bandit.core imp"
  },
  {
    "path": "bandit/core/issue.py",
    "chars": 7069,
    "preview": "#\n# Copyright 2015 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport linecache\n\nf"
  },
  {
    "path": "bandit/core/manager.py",
    "chars": 17284,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport collections\n"
  },
  {
    "path": "bandit/core/meta_ast.py",
    "chars": 1136,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport collections\n"
  },
  {
    "path": "bandit/core/metrics.py",
    "chars": 3454,
    "preview": "#\n# Copyright 2015 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport collections\n"
  },
  {
    "path": "bandit/core/node_visitor.py",
    "chars": 10830,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\nimport l"
  },
  {
    "path": "bandit/core/test_properties.py",
    "chars": 2106,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport logging\n\nfro"
  },
  {
    "path": "bandit/core/test_set.py",
    "chars": 4054,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport importlib\nim"
  },
  {
    "path": "bandit/core/tester.py",
    "chars": 6602,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport copy\nimport "
  },
  {
    "path": "bandit/core/utils.py",
    "chars": 12297,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\nimport l"
  },
  {
    "path": "bandit/formatters/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bandit/formatters/csv.py",
    "chars": 2313,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============\nCSV Formatter\n=============\n\nThis formatter outputs the issue"
  },
  {
    "path": "bandit/formatters/custom.py",
    "chars": 5363,
    "preview": "#\n# Copyright (c) 2017 Hewlett Packard Enterprise\n#\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"\n================\nCustom Fo"
  },
  {
    "path": "bandit/formatters/html.py",
    "chars": 8489,
    "preview": "# Copyright (c) 2015 Rackspace, Inc.\n# Copyright (c) 2015 Hewlett Packard Enterprise\n#\n# SPDX-License-Identifier: Apache"
  },
  {
    "path": "bandit/formatters/json.py",
    "chars": 4330,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n==============\nJSON formatter\n==============\n\nThis formatter outputs the is"
  },
  {
    "path": "bandit/formatters/sarif.py",
    "chars": 10791,
    "preview": "# Copyright (c) Microsoft.  All Rights Reserved.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n# Note: this code mostly inco"
  },
  {
    "path": "bandit/formatters/screen.py",
    "chars": 6850,
    "preview": "# Copyright (c) 2015 Hewlett Packard Enterprise\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n================\nScreen for"
  },
  {
    "path": "bandit/formatters/text.py",
    "chars": 5978,
    "preview": "# Copyright (c) 2015 Hewlett Packard Enterprise\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n==============\nText Formatt"
  },
  {
    "path": "bandit/formatters/utils.py",
    "chars": 390,
    "preview": "# Copyright (c) 2016 Rackspace, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\n\"\"\"Utility functions for formatting plugins"
  },
  {
    "path": "bandit/formatters/xml.py",
    "chars": 2753,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============\nXML Formatter\n=============\n\nThis formatter outputs the issue"
  },
  {
    "path": "bandit/formatters/yaml.py",
    "chars": 3463,
    "preview": "# Copyright (c) 2017 VMware, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n==============\nYAML Formatter\n==========="
  },
  {
    "path": "bandit/plugins/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bandit/plugins/app_debug.py",
    "chars": 2257,
    "preview": "#\n# Copyright 2015 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/asserts.py",
    "chars": 2305,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/crypto_request_no_cert_validation.py",
    "chars": 2660,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/django_sql_injection.py",
    "chars": 5203,
    "preview": "#\n# Copyright (C) 2018 [Victor Torre](https://github.com/ehooo)\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\n\nimpo"
  },
  {
    "path": "bandit/plugins/django_xss.py",
    "chars": 10302,
    "preview": "#\n# Copyright 2018 Victor Torre\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\n\nimport bandit\nfrom bandit.core impor"
  },
  {
    "path": "bandit/plugins/exec.py",
    "chars": 1357,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/general_bad_file_permissions.py",
    "chars": 3340,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/general_bind_all_interfaces.py",
    "chars": 1522,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/general_hardcoded_password.py",
    "chars": 8770,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\nimport r"
  },
  {
    "path": "bandit/plugins/general_hardcoded_tmp.py",
    "chars": 2301,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/hashlib_insecure_functions.py",
    "chars": 4330,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n======================================================================\nB324"
  },
  {
    "path": "bandit/plugins/huggingface_unsafe_download.py",
    "chars": 5899,
    "preview": "# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n================================================\nB615: Test for unsafe Huggin"
  },
  {
    "path": "bandit/plugins/injection_paramiko.py",
    "chars": 2049,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/injection_shell.py",
    "chars": 26851,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport ast\nimport r"
  },
  {
    "path": "bandit/plugins/injection_sql.py",
    "chars": 4878,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/injection_wildcard.py",
    "chars": 5016,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/insecure_ssl_tls.py",
    "chars": 10454,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport bandit\nfrom "
  },
  {
    "path": "bandit/plugins/jinja2_templates.py",
    "chars": 5806,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/logging_config_insecure_listen.py",
    "chars": 1944,
    "preview": "# Copyright (c) 2022 Rajesh Pangare\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n======================================="
  },
  {
    "path": "bandit/plugins/mako_templates.py",
    "chars": 2549,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n====================================\nB702: Test for use of mako templates\n="
  },
  {
    "path": "bandit/plugins/markupsafe_markup_xss.py",
    "chars": 3704,
    "preview": "# Copyright (c) 2025 David Salvisberg\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n====================================="
  },
  {
    "path": "bandit/plugins/pytorch_load.py",
    "chars": 2672,
    "preview": "# Copyright (c) 2024 Stacklok, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n==================================\nB614"
  },
  {
    "path": "bandit/plugins/request_without_timeout.py",
    "chars": 3087,
    "preview": "# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=======================================\nB113: Test for missing requests timeo"
  },
  {
    "path": "bandit/plugins/snmp_security_check.py",
    "chars": 3716,
    "preview": "#\n# Copyright (c) 2018 SolarWinds, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nimport bandit\nfrom bandit.core import is"
  },
  {
    "path": "bandit/plugins/ssh_no_host_key_verification.py",
    "chars": 2732,
    "preview": "# Copyright (c) 2018 VMware, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n========================================="
  },
  {
    "path": "bandit/plugins/tarfile_unsafe_members.py",
    "chars": 3929,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\n#\nr\"\"\"\n=================================\nB202: Test for tarfile.extractall\n====="
  },
  {
    "path": "bandit/plugins/trojansource.py",
    "chars": 2420,
    "preview": "#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=====================================================\nB613: TrojanSource - "
  },
  {
    "path": "bandit/plugins/try_except_continue.py",
    "chars": 3078,
    "preview": "# Copyright 2016 IBM Corp.\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apach"
  },
  {
    "path": "bandit/plugins/try_except_pass.py",
    "chars": 2910,
    "preview": "#\n# Copyright 2014 Hewlett-Packard Development Company, L.P.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n=============="
  },
  {
    "path": "bandit/plugins/weak_cryptographic_key.py",
    "chars": 5544,
    "preview": "# Copyright (c) 2015 VMware, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n========================================="
  },
  {
    "path": "bandit/plugins/yaml_load.py",
    "chars": 2404,
    "preview": "#\n# Copyright (c) 2016 Rackspace, Inc.\n#\n# SPDX-License-Identifier: Apache-2.0\nr\"\"\"\n===============================\nB506"
  },
  {
    "path": "doc/requirements.txt",
    "chars": 272,
    "preview": "# The order of packages is significant, because pip processes them in the order\n# of appearance. Changing the order has "
  },
  {
    "path": "doc/source/blacklists/blacklist_calls.rst",
    "chars": 103,
    "preview": "---------------\nblacklist_calls\n---------------\n\n.. automodule:: bandit.blacklists.calls\n   :no-index:\n"
  },
  {
    "path": "doc/source/blacklists/blacklist_imports.rst",
    "chars": 111,
    "preview": "-----------------\nblacklist_imports\n-----------------\n\n.. automodule:: bandit.blacklists.imports\n   :no-index:\n"
  },
  {
    "path": "doc/source/blacklists/index.rst",
    "chars": 3119,
    "preview": "Blacklist Plugins\n=================\n\nBandit supports built in functionality to implement blacklisting of imports and\nfun"
  },
  {
    "path": "doc/source/ci-cd/github-actions.rst",
    "chars": 2827,
    "preview": "GitHub Actions Workflow for Bandit\n==================================\n\nThis document provides a minimal complete example"
  },
  {
    "path": "doc/source/ci-cd/index.rst",
    "chars": 700,
    "preview": ".. _ci-cd:\n\nContinuous Integration and Deployment (CI/CD)\n=============================================\n\nThis section pr"
  },
  {
    "path": "doc/source/conf.py",
    "chars": 2461,
    "preview": "# SPDX-License-Identifier: Apache-2.0\nfrom datetime import datetime\nimport os\nimport sys\n\nsys.path.insert(0, os.path.abs"
  },
  {
    "path": "doc/source/config.rst",
    "chars": 9348,
    "preview": "Configuration\n=============\n\n---------------\nBandit Settings\n---------------\n\nProjects may include an INI file named `.b"
  },
  {
    "path": "doc/source/faq.rst",
    "chars": 1107,
    "preview": "Frequently Asked Questions\n==========================\n\nUnder Which Version of Python Should I Install Bandit?\n----------"
  },
  {
    "path": "doc/source/formatters/csv.rst",
    "chars": 65,
    "preview": "---\ncsv\n---\n\n.. automodule:: bandit.formatters.csv\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/custom.rst",
    "chars": 77,
    "preview": "------\ncustom\n------\n\n.. automodule:: bandit.formatters.custom\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/html.rst",
    "chars": 69,
    "preview": "----\nhtml\n----\n\n.. automodule:: bandit.formatters.html\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/index.rst",
    "chars": 1103,
    "preview": "Report Formatters\n=================\n\nBandit supports many different formatters to output various security issues in\npyth"
  },
  {
    "path": "doc/source/formatters/json.rst",
    "chars": 69,
    "preview": "----\njson\n----\n\n.. automodule:: bandit.formatters.json\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/sarif.rst",
    "chars": 73,
    "preview": "-----\nsarif\n-----\n\n.. automodule:: bandit.formatters.sarif\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/screen.rst",
    "chars": 77,
    "preview": "------\nscreen\n------\n\n.. automodule:: bandit.formatters.screen\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/text.rst",
    "chars": 69,
    "preview": "----\ntext\n----\n\n.. automodule:: bandit.formatters.text\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/xml.rst",
    "chars": 65,
    "preview": "---\nxml\n---\n\n.. automodule:: bandit.formatters.xml\n   :no-index:\n"
  },
  {
    "path": "doc/source/formatters/yaml.rst",
    "chars": 69,
    "preview": "----\nyaml\n----\n\n.. automodule:: bandit.formatters.yaml\n   :no-index:\n"
  },
  {
    "path": "doc/source/index.rst",
    "chars": 997,
    "preview": "Welcome to Bandit\n=================\n\nBandit is a tool designed to find common security issues in Python code. To do\nthis"
  },
  {
    "path": "doc/source/integrations.rst",
    "chars": 1695,
    "preview": "Integrations\n============\n\nBandit can be integrated into a wide variety of developer tools, editors,\nCI/CD systems, and "
  },
  {
    "path": "doc/source/man/bandit.rst",
    "chars": 5495,
    "preview": "======\nbandit\n======\n\nSYNOPSIS\n========\n\nbandit [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE]\n         "
  },
  {
    "path": "doc/source/plugins/b101_assert_used.rst",
    "chars": 107,
    "preview": "-----------------\nB101: assert_used\n-----------------\n\n.. automodule:: bandit.plugins.asserts\n   :no-index:"
  },
  {
    "path": "doc/source/plugins/b102_exec_used.rst",
    "chars": 99,
    "preview": "---------------\nB102: exec_used\n---------------\n\n.. automodule:: bandit.plugins.exec\n   :no-index:\n"
  },
  {
    "path": "doc/source/plugins/b103_set_bad_file_permissions.rst",
    "chars": 168,
    "preview": "------------------------------\nB103: set_bad_file_permissions\n------------------------------\n\n.. automodule:: bandit.plu"
  },
  {
    "path": "doc/source/plugins/b104_hardcoded_bind_all_interfaces.rst",
    "chars": 182,
    "preview": "-----------------------------------\nB104: hardcoded_bind_all_interfaces\n-----------------------------------\n\n.. automodu"
  },
  {
    "path": "doc/source/plugins/b105_hardcoded_password_string.rst",
    "chars": 216,
    "preview": "-------------------------------\nB105: hardcoded_password_string\n-------------------------------\n\n.. currentmodule:: band"
  },
  {
    "path": "doc/source/plugins/b106_hardcoded_password_funcarg.rst",
    "chars": 220,
    "preview": "--------------------------------\nB106: hardcoded_password_funcarg\n--------------------------------\n\n.. currentmodule:: b"
  },
  {
    "path": "doc/source/plugins/b107_hardcoded_password_default.rst",
    "chars": 220,
    "preview": "--------------------------------\nB107: hardcoded_password_default\n--------------------------------\n\n.. currentmodule:: b"
  },
  {
    "path": "doc/source/plugins/b108_hardcoded_tmp_directory.rst",
    "chars": 158,
    "preview": "-----------------------------\nB108: hardcoded_tmp_directory\n-----------------------------\n\n.. automodule:: bandit.plugin"
  },
  {
    "path": "doc/source/plugins/b109_password_config_option_not_marked_secret.rst",
    "chars": 2052,
    "preview": "----------------------------------------------\nB109: password_config_option_not_marked_secret\n--------------------------"
  },
  {
    "path": "doc/source/plugins/b110_try_except_pass.rst",
    "chars": 128,
    "preview": "---------------------\nB110: try_except_pass\n---------------------\n\n.. automodule:: bandit.plugins.try_except_pass\n   :no"
  },
  {
    "path": "doc/source/plugins/b111_execute_with_run_as_root_equals_true.rst",
    "chars": 1744,
    "preview": "------------------------------------------\nB111: execute_with_run_as_root_equals_true\n----------------------------------"
  },
  {
    "path": "doc/source/plugins/b112_try_except_continue.rst",
    "chars": 144,
    "preview": "-------------------------\nB112: try_except_continue\n-------------------------\n\n.. automodule:: bandit.plugins.try_except"
  },
  {
    "path": "doc/source/plugins/b113_request_without_timeout.rst",
    "chars": 160,
    "preview": "-----------------------------\nB113: request_without_timeout\n-----------------------------\n\n.. automodule:: bandit.plugin"
  },
  {
    "path": "doc/source/plugins/b201_flask_debug_true.rst",
    "chars": 125,
    "preview": "----------------------\nB201: flask_debug_true\n----------------------\n\n.. automodule:: bandit.plugins.app_debug\n   :no-in"
  },
  {
    "path": "doc/source/plugins/b202_tarfile_unsafe_members.rst",
    "chars": 156,
    "preview": "----------------------------\nB202: tarfile_unsafe_members\n----------------------------\n\n.. automodule:: bandit.plugins.t"
  },
  {
    "path": "doc/source/plugins/b324_hashlib.rst",
    "chars": 115,
    "preview": "-------------\nB324: hashlib\n-------------\n\n.. automodule:: bandit.plugins.hashlib_insecure_functions\n   :no-index:\n"
  },
  {
    "path": "doc/source/plugins/b501_request_with_no_cert_validation.rst",
    "chars": 194,
    "preview": "-------------------------------------\nB501: request_with_no_cert_validation\n-------------------------------------\n\n.. au"
  },
  {
    "path": "doc/source/plugins/b502_ssl_with_bad_version.rst",
    "chars": 186,
    "preview": "--------------------------\nB502: ssl_with_bad_version\n--------------------------\n\n.. currentmodule:: bandit.plugins.inse"
  },
  {
    "path": "doc/source/plugins/b503_ssl_with_bad_defaults.rst",
    "chars": 190,
    "preview": "---------------------------\nB503: ssl_with_bad_defaults\n---------------------------\n\n.. currentmodule:: bandit.plugins.i"
  },
  {
    "path": "doc/source/plugins/b504_ssl_with_no_version.rst",
    "chars": 182,
    "preview": "-------------------------\nB504: ssl_with_no_version\n-------------------------\n\n.. currentmodule:: bandit.plugins.insecur"
  },
  {
    "path": "doc/source/plugins/b505_weak_cryptographic_key.rst",
    "chars": 156,
    "preview": "----------------------------\nB505: weak_cryptographic_key\n----------------------------\n\n.. automodule:: bandit.plugins.w"
  },
  {
    "path": "doc/source/plugins/b506_yaml_load.rst",
    "chars": 104,
    "preview": "---------------\nB506: yaml_load\n---------------\n\n.. automodule:: bandit.plugins.yaml_load\n   :no-index:\n"
  },
  {
    "path": "doc/source/plugins/b507_ssh_no_host_key_verification.rst",
    "chars": 180,
    "preview": "----------------------------------\nB507: ssh_no_host_key_verification\n----------------------------------\n\n.. automodule:"
  },
  {
    "path": "doc/source/plugins/b508_snmp_insecure_version.rst",
    "chars": 198,
    "preview": "---------------------------\nB508: snmp_insecure_version\n---------------------------\n\n.. currentmodule:: bandit.plugins.s"
  },
  {
    "path": "doc/source/plugins/b509_snmp_weak_cryptography.rst",
    "chars": 192,
    "preview": "----------------------------\nB509: snmp_weak_cryptography\n----------------------------\n\n.. currentmodule:: bandit.plugin"
  },
  {
    "path": "doc/source/plugins/b601_paramiko_calls.rst",
    "chars": 128,
    "preview": "--------------------\nB601: paramiko_calls\n--------------------\n\n.. automodule:: bandit.plugins.injection_paramiko\n   :no"
  },
  {
    "path": "doc/source/plugins/b602_subprocess_popen_with_shell_equals_true.rst",
    "chars": 261,
    "preview": "---------------------------------------------\nB602: subprocess_popen_with_shell_equals_true\n----------------------------"
  },
  {
    "path": "doc/source/plugins/b603_subprocess_without_shell_equals_true.rst",
    "chars": 249,
    "preview": "------------------------------------------\nB603: subprocess_without_shell_equals_true\n----------------------------------"
  },
  {
    "path": "doc/source/plugins/b604_any_other_function_with_shell_equals_true.rst",
    "chars": 269,
    "preview": "-----------------------------------------------\nB604: any_other_function_with_shell_equals_true\n------------------------"
  },
  {
    "path": "doc/source/plugins/b605_start_process_with_a_shell.rst",
    "chars": 209,
    "preview": "--------------------------------\nB605: start_process_with_a_shell\n--------------------------------\n\n.. currentmodule:: b"
  },
  {
    "path": "doc/source/plugins/b606_start_process_with_no_shell.rst",
    "chars": 213,
    "preview": "---------------------------------\nB606: start_process_with_no_shell\n---------------------------------\n\n.. currentmodule:"
  },
  {
    "path": "doc/source/plugins/b607_start_process_with_partial_path.rst",
    "chars": 229,
    "preview": "-------------------------------------\nB607: start_process_with_partial_path\n-------------------------------------\n\n.. cu"
  },
  {
    "path": "doc/source/plugins/b608_hardcoded_sql_expressions.rst",
    "chars": 156,
    "preview": "-------------------------------\nB608: hardcoded_sql_expressions\n-------------------------------\n\n.. automodule:: bandit."
  },
  {
    "path": "doc/source/plugins/b609_linux_commands_wildcard_injection.rst",
    "chars": 185,
    "preview": "---------------------------------------\nB609: linux_commands_wildcard_injection\n---------------------------------------\n"
  },
  {
    "path": "doc/source/plugins/b610_django_extra_used.rst",
    "chars": 178,
    "preview": "-----------------------\nB610: django_extra_used\n-----------------------\n\n.. currentmodule:: bandit.plugins.django_sql_in"
  },
  {
    "path": "doc/source/plugins/b611_django_rawsql_used.rst",
    "chars": 182,
    "preview": "------------------------\nB611: django_rawsql_used\n------------------------\n\n.. currentmodule:: bandit.plugins.django_sql"
  },
  {
    "path": "doc/source/plugins/b612_logging_config_insecure_listen.rst",
    "chars": 188,
    "preview": "------------------------------------\nB612: logging_config_insecure_listen\n------------------------------------\n\n.. autom"
  },
  {
    "path": "doc/source/plugins/b613_trojansource.rst",
    "chars": 116,
    "preview": "------------------\nB613: trojansource\n------------------\n\n.. automodule:: bandit.plugins.trojansource\n   :no-index:\n"
  },
  {
    "path": "doc/source/plugins/b614_pytorch_load.rst",
    "chars": 116,
    "preview": "------------------\nB614: pytorch_load\n------------------\n\n.. automodule:: bandit.plugins.pytorch_load\n   :no-index:\n"
  },
  {
    "path": "doc/source/plugins/b615_huggingface_unsafe_download.rst",
    "chars": 176,
    "preview": "---------------------------------\nB615: huggingface_unsafe_download\n---------------------------------\n\n.. automodule:: b"
  },
  {
    "path": "doc/source/plugins/b701_jinja2_autoescape_false.rst",
    "chars": 153,
    "preview": "-----------------------------\nB701: jinja2_autoescape_false\n-----------------------------\n\n.. automodule:: bandit.plugin"
  },
  {
    "path": "doc/source/plugins/b702_use_of_mako_templates.rst",
    "chars": 145,
    "preview": "---------------------------\nB702: use_of_mako_templates\n---------------------------\n\n.. automodule:: bandit.plugins.mako"
  },
  {
    "path": "doc/source/plugins/b703_django_mark_safe.rst",
    "chars": 164,
    "preview": "----------------------\nB703: django_mark_safe\n----------------------\n\n.. currentmodule:: bandit.plugins.django_xss\n\n.. a"
  },
  {
    "path": "doc/source/plugins/b704_markupsafe_markup_xss.rst",
    "chars": 152,
    "preview": "---------------------------\nB704: markupsafe_markup_xss\n---------------------------\n\n.. automodule:: bandit.plugins.mark"
  },
  {
    "path": "doc/source/plugins/index.rst",
    "chars": 4085,
    "preview": "Test Plugins\n============\n\nBandit supports many different tests to detect various security issues in\npython code. These "
  },
  {
    "path": "doc/source/start.rst",
    "chars": 3383,
    "preview": "Getting Started\n===============\n\nInstallation\n------------\n\nBandit is distributed on PyPI. The best way to install it is"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 329,
    "preview": "FROM python:3.12-alpine\n\n# Install Git (required for pbr versioning)\nRUN apk add --no-cache git\n\n# Copy the source code "
  },
  {
    "path": "examples/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/assert.py",
    "chars": 12,
    "preview": "assert True\n"
  },
  {
    "path": "examples/binding.py",
    "chars": 126,
    "preview": "import socket\n\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.bind(('0.0.0.0', 31137))\ns.bind(('192.168.0.1', 8"
  },
  {
    "path": "examples/cipher-modes.py",
    "chars": 257,
    "preview": "from cryptography.hazmat.primitives.ciphers.modes import CBC\nfrom cryptography.hazmat.primitives.ciphers.modes import EC"
  },
  {
    "path": "examples/ciphers.py",
    "chars": 3623,
    "preview": "from Crypto.Cipher import ARC2 as pycrypto_arc2\nfrom Crypto.Cipher import ARC4 as pycrypto_arc4\nfrom Crypto.Cipher impor"
  },
  {
    "path": "examples/crypto-md5.py",
    "chars": 1339,
    "preview": "from cryptography.hazmat.primitives import hashes\nfrom Crypto.Hash import MD2 as pycrypto_md2\nfrom Crypto.Hash import MD"
  },
  {
    "path": "examples/dill.py",
    "chars": 253,
    "preview": "import dill\nimport io\n\n# dill\npick = dill.dumps({'a': 'b', 'c': 'd'})\nprint(dill.loads(pick))\n\nfile_obj = io.BytesIO()\nd"
  },
  {
    "path": "examples/django_sql_injection_extra.py",
    "chars": 1438,
    "preview": "from django.contrib.auth.models import User\n\nUser.objects.filter(username='admin').extra(\n    select={'test': 'secure'},"
  },
  {
    "path": "examples/django_sql_injection_raw.py",
    "chars": 663,
    "preview": "from django.db.models.expressions import RawSQL\nfrom django.contrib.auth.models import User\n\nUser.objects.annotate(val=R"
  },
  {
    "path": "examples/eval.py",
    "chars": 283,
    "preview": "import os\n\nprint(eval(\"1+1\"))\nprint(eval(\"os.getcwd()\"))\nprint(eval(\"os.chmod('%s', 0777)\" % 'test.txt'))\n\n\n# A user-def"
  },
  {
    "path": "examples/exec.py",
    "chars": 16,
    "preview": "exec(\"do evil\")\n"
  },
  {
    "path": "examples/flask_debug.py",
    "chars": 195,
    "preview": "from flask import Flask\n\napp = Flask(__name__)\n\n@app.route('/')\ndef main():\n    raise\n\n#bad\napp.run(debug=True)\n\n#okay\na"
  },
  {
    "path": "examples/ftplib.py",
    "chars": 315,
    "preview": "from ftplib import FTP\nfrom ftplib import FTP_TLS\n\n\n# bad\nftp = FTP('ftp.debian.org')\nftp.login()\n\nftp.cwd('debian')\nftp"
  },
  {
    "path": "examples/hardcoded-passwords.py",
    "chars": 2958,
    "preview": "# Possible hardcoded password: 'class_password'\n# Severity: Low   Confidence: Medium\nclass SomeClass:\n    password = \"cl"
  },
  {
    "path": "examples/hardcoded-tmp.py",
    "chars": 299,
    "preview": "with open('/tmp/abc', 'w') as f:\n    f.write('def')\n\n# ok\nwith open('/abc/tmp', 'w') as f:\n    f.write('def')\n\nwith open"
  },
  {
    "path": "examples/hashlib_new_insecure_functions.py",
    "chars": 459,
    "preview": "import hashlib\n\nhashlib.new('md5')\n\nhashlib.new('md4', b'test')\n\nhashlib.new(name='md5', data=b'test')\n\nhashlib.new('MD4"
  },
  {
    "path": "examples/httpoxy_cgihandler.py",
    "chars": 324,
    "preview": "import requests\nimport wsgiref.handlers\n\ndef application(environ, start_response):\n    r = requests.get('https://192.168"
  },
  {
    "path": "examples/httpoxy_twisted_directory.py",
    "chars": 232,
    "preview": "from twisted.internet import reactor\nfrom twisted.web import static, server, twcgi\n\nroot = static.File(\"/root\")\nroot.put"
  },
  {
    "path": "examples/httpoxy_twisted_script.py",
    "chars": 240,
    "preview": "from twisted.internet import reactor\nfrom twisted.web import static, server, twcgi\n\nroot = static.File(\"/root\")\nroot.put"
  },
  {
    "path": "examples/huggingface_unsafe_download.py",
    "chars": 3949,
    "preview": "from datasets import load_dataset\nfrom huggingface_hub import hf_hub_download, snapshot_download\nfrom transformers impor"
  },
  {
    "path": "examples/imports-aliases.py",
    "chars": 295,
    "preview": "from subprocess import Popen as pop\nimport hashlib as h\nimport hashlib as hh\nimport hashlib as hhh\nimport hashlib as hhh"
  },
  {
    "path": "examples/imports-from.py",
    "chars": 146,
    "preview": "from subprocess import Popen\n\nfrom ..foo import sys\nfrom . import sys\nfrom .. import sys\nfrom .. import subprocess\nfrom "
  },
  {
    "path": "examples/imports-function.py",
    "chars": 353,
    "preview": "os = __import__(\"os\")\npickle = __import__(\"pickle\")\nsys = __import__(\"sys\")\nsubprocess = __import__(\"subprocess\")\n\n# thi"
  },
  {
    "path": "examples/imports-with-importlib.py",
    "chars": 546,
    "preview": "import importlib\na = importlib.import_module('os')\nb = importlib.import_module('pickle')\nc = importlib.__import__('sys')"
  },
  {
    "path": "examples/imports.py",
    "chars": 53,
    "preview": "import os\nimport pickle\nimport sys\nimport subprocess\n"
  },
  {
    "path": "examples/init-py-test/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/init-py-test/subdirectory-okay.py",
    "chars": 161,
    "preview": "# A sample test file in a subdirectory and its parents both containing\n# an __init__.py file outlined in bug/1743042.\npr"
  },
  {
    "path": "examples/jinja2_templating.py",
    "chars": 991,
    "preview": "import jinja2\nfrom jinja2 import Environment, select_autoescape\ntemplateLoader = jinja2.FileSystemLoader( searchpath=\"/\""
  },
  {
    "path": "examples/jsonpickle.py",
    "chars": 196,
    "preview": "import jsonpickle\n\n\npick = jsonpickle.encode({'a': 'b', 'c': 'd'})\n\nprint(jsonpickle.decode(pick))\n\nprint(jsonpickle.unp"
  },
  {
    "path": "examples/logging_config_insecure_listen.py",
    "chars": 55,
    "preview": "import logging.config\n\nt = logging.config.listen(9999)\n"
  },
  {
    "path": "examples/long_set.py",
    "chars": 65560,
    "preview": "# This file contains a single long_set with 7276 'a' elements\nlong_set = {\n    'a',\n    'a',\n    'a',\n    'a',\n    'a',\n"
  },
  {
    "path": "examples/mako_templating.py",
    "chars": 292,
    "preview": "from mako.template import Template\nimport mako\n\nfrom mako import template\n\nTemplate(\"hello\")\n\n# XXX(fletcher): for some "
  },
  {
    "path": "examples/mark_safe.py",
    "chars": 102,
    "preview": "from django.utils import safestring\n\nmystr = '<b>Hello World</b>'\nmystr = safestring.mark_safe(mystr)\n"
  },
  {
    "path": "examples/mark_safe_insecure.py",
    "chars": 4771,
    "preview": "import os\nfrom django.utils import safestring\n\n\ndef insecure_function(text, cls=''):\n    return '<h1 class=\"{cls}\">{text"
  },
  {
    "path": "examples/mark_safe_secure.py",
    "chars": 2184,
    "preview": "import os\nfrom django.utils import safestring\n\nsafestring.mark_safe('<b>secure</b>')\nsafestring.SafeText('<b>secure</b>'"
  },
  {
    "path": "examples/markupsafe_markup_xss.py",
    "chars": 458,
    "preview": "import flask\nfrom markupsafe import Markup, escape\n\ncontent = \"<script>alert('Hello, world!')</script>\"\nMarkup(f\"unsafe "
  },
  {
    "path": "examples/markupsafe_markup_xss_allowed_calls.py",
    "chars": 224,
    "preview": "from bleach import clean\nfrom markupsafe import Markup\n\ncontent = \"<script>alert('Hello, world!')</script>\"\nMarkup(clean"
  },
  {
    "path": "examples/markupsafe_markup_xss_extend_markup_names.py",
    "chars": 176,
    "preview": "from markupsafe import Markup\nfrom webhelpers.html import literal\n\ncontent = \"<script>alert('Hello, world!')</script>\"\nM"
  },
  {
    "path": "examples/marshal_deserialize.py",
    "chars": 237,
    "preview": "import marshal\nimport tempfile\n\n\nserialized = marshal.dumps({'a': 1})\nprint(marshal.loads(serialized))\n\nfile_obj = tempf"
  },
  {
    "path": "examples/mktemp.py",
    "chars": 152,
    "preview": "from tempfile import mktemp\nimport tempfile.mktemp as mt\nimport tempfile as tmp\n\nfoo = 'hi'\n\nmktemp(foo)\ntempfile.mktemp"
  },
  {
    "path": "examples/multiline_statement.py",
    "chars": 282,
    "preview": "import subprocess\n\nsubprocess.check_output(\"/some_command\",\n                        \"args\",\n                        shel"
  }
]

// ... and 91 more files (download for full content)

About this extraction

This page contains the full source code of the PyCQA/bandit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 291 files (778.0 KB), approximately 206.9k tokens, and a symbol index with 709 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!