Bandit percorre a árvore sintática do código Python e sinaliza padrões associados a riscos, como uso inseguro de subprocessos, hashes fracos e possíveis segredos. O resultado é um ponto de investigação, não uma prova automática de vulnerabilidade.

Ele é uma ferramenta de análise estática de segurança, também chamada de SAST. Como trabalha sobre a árvore sintática, consegue distinguir construções da linguagem melhor do que uma busca textual simples. Ainda assim, não conhece toda a arquitetura, a origem real dos dados nem os controles externos ao arquivo. A equipe precisa interpretar cada alerta dentro do fluxo da aplicação.

Executar a análise

python -m pip install "bandit[toml]"
bandit -r src
bandit -r src --severity-level high

Comece vendo todos os achados e defina o limite da CI depois de entender o perfil do projeto. Não configure severidade alta apenas para esconder alertas médios relevantes.

Um achado sobre subprocess pode ser seguro quando os argumentos são constantes e shell=False, mas crítico quando texto do usuário chega ao shell. Investigue origem, transformação e destino do dado. O artigo sobre segurança de APIs Python ajuda a pensar nessas fronteiras.

O relatório apresenta o arquivo, a linha, o identificador do teste, a severidade e a confiança. Severidade estima o impacto potencial; confiança expressa quão seguramente o plugin reconheceu o padrão. Nenhuma das duas mede a probabilidade de exploração no seu ambiente. Um achado de severidade média em uma rota pública pode merecer prioridade maior que um achado alto em uma ferramenta interna isolada.

Para saída consumida por automação, escolha um formato explícito:

bandit -r src -f json -o bandit-report.json
bandit -r src -f sarif -o bandit-report.sarif

Não publique relatórios como artefatos públicos sem revisá-los. Eles incluem caminhos, trechos de código e detalhes que podem ajudar alguém a mapear a aplicação. Restrinja o acesso e defina uma retenção compatível com o processo de segurança.

Configurar o projeto em pyproject.toml

Com o extra toml, o Bandit pode ler opções do pyproject.toml. Centralizar a configuração evita diferenças entre a máquina do desenvolvedor e a CI:

[tool.bandit]
exclude_dirs = ["tests/fixtures", ".venv"]
skips = ["B101"]

Uma exclusão precisa ter uma justificativa verificável. Ignorar B101, associado a assert, por exemplo, só é razoável quando a equipe entende que o código analisado não depende de asserts para validação de segurança e que a política vale para aquele conjunto de arquivos. Excluir todo o diretório de testes também pode esconder utilitários executados em pipelines. Prefira excluir fixtures deliberadamente inseguras em vez de uma árvore inteira.

Também é possível selecionar testes com -t ou ignorá-los com -s. Essas opções são úteis para uma investigação pontual, mas uma política permanente deve ficar versionada. Assim, qualquer mudança de cobertura aparece na revisão de código.

Interpretar e corrigir achados comuns

O objetivo da triagem é descobrir se existe um caminho explorável e eliminar a causa. Alguns grupos aparecem com frequência:

  • comandos e processos: passe uma lista de argumentos para subprocess.run, mantenha shell=False e valide entradas por uma lista permitida quando elas influenciam a operação;
  • arquivos temporários: use APIs que criam arquivos com nomes imprevisíveis e permissões adequadas, em vez de montar caminhos previsíveis;
  • criptografia e hashes: não use MD5 ou SHA-1 para senhas ou decisões de segurança; escolha uma biblioteca e um algoritmo adequados ao caso;
  • desserialização: trate pickle como execução de código e nunca carregue conteúdo de origem não confiável;
  • TLS: não desative a validação de certificado para “resolver” um ambiente; corrija a cadeia de confiança;
  • segredos aparentes: retire credenciais do código e faça rotação se um valor real foi versionado.

Considere este padrão perigoso:

import subprocess


def consultar(host: str) -> None:
    subprocess.run(f"ping -c 1 {host}", shell=True, check=True)

Validar o texto com uma expressão regular reduz alguns casos, mas ainda mantém uma superfície difícil de raciocinar. Separar os argumentos evita que o shell interprete metacaracteres:

import ipaddress
import subprocess


def consultar(host: str) -> None:
    endereco = str(ipaddress.ip_address(host))
    subprocess.run(["ping", "-c", "1", endereco], check=True)

Essa mudança também deixa clara a política: a função aceita endereço IP, não uma linha de comando arbitrária. Limites de tempo, privilégios mínimos e regras de rede continuam necessários conforme o ambiente.

Tratar falsos positivos sem perder sinal

Antes de silenciar, reproduza o caminho, identifique quem controla o valor e registre por que o controle existente é suficiente. Quando a exceção for realmente necessária, use # nosec na linha e informe o teste específico, como # nosec B603. Uma justificativa próxima facilita revisões futuras. Um # nosec genérico pode ocultar novos plugins que passem a alertar na mesma linha.

Revise exceções periodicamente. Código muda, funções antes internas tornam-se públicas e validações podem desaparecer. Uma busca por nosec no pull request torna o aumento de exceções visível, mas não substitui a análise do contexto.

Baselines guardam achados existentes para que uma adoção inicial não bloqueie toda a equipe. Gere a baseline, proteja-a como código e estabeleça um plano de redução. Ela não deve virar um arquivo esquecido que aceita indefinidamente qualquer risco antigo. Ao modificar uma área registrada, reavalie os achados correspondentes.

Colocar Bandit na CI

Uma verificação mínima instala uma versão controlada e analisa somente o código do projeto:

python -m pip install "bandit[toml]==1.8.6"
bandit -c pyproject.toml -r src

Fixar a versão torna o resultado reproduzível. Atualizações planejadas são importantes porque novos testes e correções chegam à ferramenta. Faça a atualização em um pull request próprio, leia as mudanças e triate novos alertas, em vez de manter uma versão antiga para preservar uma execução verde.

Na política de merge, diferencie falha da ferramenta de ausência de achados. Se a instalação falhar ou o diretório estiver errado, a etapa deve falhar de forma clara. Armazene o relatório apenas quando houver controle de acesso e deixe o log suficiente para a equipe localizar o problema.

Bandit funciona melhor junto de outras camadas: lint e testes encontram defeitos gerais, análise de dependências identifica pacotes vulneráveis, secret scanning procura credenciais e testes dinâmicos exercitam a aplicação em execução. Modelagem de ameaças e revisão humana conectam essas evidências ao que o sistema realmente protege.

Integrar sem acumular exceções

Execute Bandit em commits e na CI. Em bases antigas, uma baseline pode permitir adoção gradual, desde que novos achados sejam bloqueados e o passivo tenha responsável. Evite comentários genéricos para silenciar uma linha. Registre o identificador do teste e por que o caso é seguro.

Bandit não examina vulnerabilidades conhecidas nas dependências. Para isso, use pip-audit. Também não substitui testes de autorização, configuração segura ou revisão arquitetural.

A documentação oficial do Bandit e a referência oficial de configuração, consultadas em 22 de julho de 2026, descrevem plugins, severidade, confiança, formatos e baselines. O valor vem da triagem consistente e da correção da causa, não da ausência artificial de alertas.