50 · Os códigos de um relatório: QG e QC¶
Um relatório do stalwart verify ou de uma varredura traz achados sob dois tipos de código. Os códigos QG
são do caçador de bugs: caminhos através das suas regras, encontrados no grafo dos agentes, no rulebook e no
roteador. Os códigos QC são das verificações de código: problemas em como o código das suas ferramentas
lida com a rede e com credenciais. Este capítulo diz em que os dois diferem, lista toda regra QC e diz como
cada família se relaciona com os padrões sob os quais uma equipe de segurança arquiva achados.
Idiomas
O seletor lê turnos escritos em inglês e em português do Brasil (pt-BR). O idioma é escolhido, nunca adivinhado a partir do turno: na página Settings do console (Language the selector reads), em language numa requisição de plano, ou no settings.language do seu arquivo de vocabulário; sem nenhum deles, inglês. Um turno em português pode ser digitado com os acentos ou sem eles. O português europeu não é uma gramática que o seletor tenha, e um turno em qualquer outra língua não é lido.
Duas famílias¶
QG -- o caçador de bugs |
QC -- as verificações de código |
|
|---|---|---|
| Lê | o grafo dos agentes, o rulebook ou a planilha de regras, o catálogo, o roteador na frente deles | os arquivos-fonte da pasta onde está o agent.yaml: Python, JavaScript, TypeScript e Go |
| Roda | nos servidores da Stalwart, como um job hunt |
na sua máquina, no runtime licenciado; o seu código nunca sai dela, só a contagem de achados por regra vai com o registro |
| Um achado traz | a regra, a severidade e o tipo, o local no arquivo que você edita, o fluxo, uma reprodução, uma correção conferida e as entradas OWASP | a regra, o CWE, o arquivo e a linha, o caminho que o valor percorreu até ali e uma frase |
| Reprova o gate | pelas condições do gate: um achado Critical novo, uma linha quebrada das suas próprias tabelas e as outras do capítulo 28; o perfil de qualidade de um projeto pode pedir mais | todo achado, sem nível, sem dispensa e sem comentário de supressão: só mudar o código o resolve |
| Guardado ao longo do tempo | num projeto, contra a sua linha de base, com as decisões de uma pessoa -- falso positivo, risco aceito com validade (capítulo 51) | não guardado: a próxima execução lê o código como ele estiver |
A primeira é uma pergunta sobre rotas: se um turno, um documento ou outro agente pode fazer o agente fazer o que as suas regras dizem que ele não deve. A segunda é uma pergunta sobre código: se uma ferramenta envia dados em texto claro, confia num servidor que deveria verificar ou guarda um segredo onde ele pode vazar. Uma resposta limpa a uma não diz nada sobre a outra.
As regras QG¶
O caçador de bugs tem 49 regras, em quatro faixas:
QG0xxsão encontradas numa política ou num grafo de agentes: um caminho através de uma regra.QG1xxsão itens de revisão, security hotspots: uma pessoa decide se cada um é um problema.QG2xxdizem o que uma varredura não conseguiu decidir ou descrever.QG201Undecided é a que um relatório limpo ainda precisa ser lido para encontrar.QG3xxsão encontradas num host construído a partir do seu catálogo e do roteador na frente dele.
As páginas de regras têm uma página por regra: quando é levantada, por que importa, como corrigir, a severidade e as entradas OWASP. O capítulo 28 lê um achado linha por linha.
As regras QC¶
Toda regra que as verificações de código rodam, a partir do pacote de regras que o runtime lê:
Segurança de rede
| Regra | CWE | Levantada onde o seu código | O que a resolve |
|---|---|---|---|
QC001 |
CWE-1327 |
abre um socket de escuta -- um servidor, uma porta ligada -- que não seja um servidor MCP em loopback sobre o transporte http declarado |
não escute a partir do código de ferramenta; um servidor MCP roda em stdio, ou em loopback com --transport http |
QC002 |
CWE-295 |
desliga a verificação TLS ou substitui o repositório de confiança -- verify=False, rejectUnauthorized: false, InsecureSkipVerify, ssl.CERT_NONE, um bundle de CA próprio |
remova a configuração; o repositório de confiança do sistema é o que as verificações aceitam |
QC003 |
CWE-319 |
envia uma requisição por http:// ou ws:// a um host que não é loopback |
use https:// ou wss:// |
QC004 |
CWE-918 |
envia uma requisição a um endereço tirado de um argumento de ferramenta ou de uma resposta, sem conferi-lo antes contra uma lista constante | fixe o host no código, ou confira o valor contra uma lista constante (if host in ALLOWED) antes da requisição |
QC005 |
CWE-441 |
envia uma requisição a um host constante fora da lista de saída declarada com o catálogo (--egress) |
acrescente o host à lista de saída, ou remova a requisição |
QC006 |
CWE-693 |
contorna o proxy do ambiente -- trust_env=False, uma configuração de proxy apagada, um socket cru |
deixe as configurações de proxy como o ambiente as dá, e use um cliente HTTP |
QC007 |
CWE-494 |
roda código que buscou, importa código de uma URL ou instala pacotes em tempo de execução | declare a dependência e instale-a antes de o agente rodar |
Credenciais
| Regra | CWE | Levantada onde o seu código | O que a resolve |
|---|---|---|---|
QC010 |
CWE-798 |
escreve um segredo no código-fonte -- um token, uma senha, uma chave num formato conhecido | leia-o de uma variável de ambiente em tempo de execução, e revogue o que foi escrito |
QC011 |
CWE-532 |
põe um segredo numa linha de log, na mensagem de uma exceção ou no resultado de uma ferramenta | registre e devolva para que o segredo foi usado, nunca o segredo |
QC012 |
CWE-598 |
põe um segredo na query string de uma URL | envie-o num cabeçalho |
QC013 |
CWE-312 |
guarda um segredo num armazenamento próprio -- um arquivo, um cache, um banco de dados | leia-o da sua variável de ambiente a cada vez que precisar |
QC014 |
CWE-522 |
lê uma credencial de outro lugar que não uma variável de ambiente -- um keyring, um arquivo .env, um .netrc, os cookies de um navegador, um arquivo de credenciais como ~/.aws/credentials |
leia-a de uma variável de ambiente com que o processo é iniciado |
QC015 |
CWE-522 |
roda o seu próprio fluxo de login -- uma troca OAuth, um pedido de token | deixe o gateway fazer o login (capítulo 37) e passe à ferramenta o token que ele obtém |
Código que as verificações não conseguem ler
| Regra | CWE | Levantada onde o seu código | O que a resolve |
|---|---|---|---|
QC020 |
-- | não pode ser lido -- um arquivo que não é analisável, código minificado ou gerado, uma extensão nativa, uma linguagem para a qual as verificações não têm regras, código rodado a partir de uma string | mantenha o código-fonte legível na pasta, ou tire dela o que não pode ser lido |
Um segredo é um valor lido de uma variável de ambiente cujo nome contém uma palavra como token, secret,
password ou api_key -- mas não um que só diz onde um segredo está, como TOKEN_FILE --, ou um literal
num formato de chave conhecido. Um argumento de ferramenta é um valor que o modelo ou a pessoa dá a uma função
de ferramenta. Uma requisição é uma chamada de um cliente HTTP, de um socket ou de um fetch.
QC005 precisa de uma lista de saída para comparar: stalwart catalogue import recebe uma com --egress.
O stalwart verify não tem nenhuma, então não levanta QC005, e todo socket de escuta é QC001.
Lendo um achado QC¶
QC002 CWE-295 shop/tracking.py:8 This code turns TLS verification off (`verify=False`), at shop/tracking.py:8.
shop/tracking.py:8 turns TLS verification off (`verify=False`)
A primeira linha é a regra, o CWE, o local e a frase. As linhas abaixo são o caminho: de onde o valor veio, cada função por que passou e onde terminou. Um achado sobre um segredo num log começa onde o segredo foi lido; um sobre o destino de uma requisição começa no argumento de ferramenta de onde ele veio. O capítulo 46 mostra este achado num relatório completo.
As verificações seguem um valor através das suas funções, então um achado pode estar num arquivo que nenhuma ferramenta importa diretamente. Elas leem todo arquivo-fonte da pasta, de ferramenta ou não, já que uma ferramenta pode importar qualquer um deles.
Os padrões¶
Um achado QG traz as entradas do OWASP Top 10 for LLM Applications e do OWASP Top 10 for Agentic
Applications de que é uma instância, com a edição (LLM01:2026, ASI04:2026), no relatório e nas
taxonomies do SARIF (capítulo 28). O capítulo 39 tem o inverso:
quais regras cobrem cada entrada.
Um achado QC traz o CWE da fraqueza no seu código -- CWE-295 é validação imprópria de certificado --
e nenhuma entrada OWASP: as listas OWASP são sobre o que um agente pode ser levado a fazer, e uma regra QC é
sobre como um trecho de código é escrito. QC020 não tem CWE: diz que as verificações não conseguiram ler o
código, não que o código é fraco.
Os limites¶
- As verificações de código leem segurança de rede e tratamento de credenciais, em Python, JavaScript, TypeScript e Go, e nada mais sobre o que o seu código faz: uma ferramenta que calcula o reembolso errado passa por elas.
- Código que as verificações não conseguem ler é um achado,
QC020, nunca uma aprovação: um arquivo que não é analisável, código minificado, uma extensão nativa ou código rodado a partir de uma string reprova o gate até ficar legível ou sair da pasta. - Um relatório
QClimpo não é um relatórioQGlimpo, nem o contrário: cada um responde à sua própria pergunta.