Criar conta gratuita
Segurança do código de aplicações LLM

A saída do seu modelo é entrada não fiável. Descubra onde o seu código se esquece disso.

Análise estática do código à volta do seu LLM — o código que constrói o prompt, chama o modelo e faz alguma coisa com a resposta. Não o modelo. Não a resistência do prompt a um jailbreak. O código.

O plano gratuito cobre 3 projetos e 30 análises por mês, sem limite de utilizadores e sem cartão de crédito. Esta análise está incluída.

O problema

Um modelo não é uma biblioteca. É um interpretador não fiável: entrega-lhe uma cadeia de texto e ele devolve outra. Tudo o que influenciou essa cadeia — o prompt do próprio utilizador, uma página que lhe foi mostrada, um documento que lhe foi dado, o resultado de outra ferramenta — influenciou a resposta.

A resposta é inofensiva até o código lhe dar uma capacidade. O perigo não é um modelo ter dito alguma coisa; é um programa ter acreditado. Cada ponto em que um programa trata texto gerado como código, como um comando, como uma consulta, como um caminho ou como um URL é uma injeção com mais um salto — e, ao contrário da questão de saber se um prompt pode ser contornado por jailbreak, esse salto é visível no código-fonte.

O que o Cybseco procura

Onde a saída do modelo chega a algo que age. Estas são as categorias, severidades e identificadores CWE do próprio motor.

Execução de código — CWE-94
crítica
eval, exec, compile, new Function, pickle.loads, yaml.load — a resposta torna-se um programa.
Uma shell — CWE-78
crítica
os.system, subprocess, child_process.exec, execSync — a resposta torna-se um comando.
Uma consulta SQL — CWE-89
alta
execute, raw, createQuery — o text-to-SQL é exatamente este padrão, e DROP TABLE é uma continuação plausível.
Um caminho do sistema de ficheiros — CWE-22
alta
open, readFile, shutil.rmtree, unlink — ../../etc/passwd também é uma continuação plausível.
Um pedido de saída — CWE-918
alta
requests, httpx, fetch, axios, urlopen — falsificação de pedidos do lado do servidor, escolhida pelo modelo.

Um exemplo concreto

Nove linhas, e toda a forma do risco.

from openai import OpenAI
client = OpenAI()

def run_plan(task: str):
    answer = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": task}],
    )
    exec(answer.choices[0].message.content)
Origem
client.chat.completions.create(…) — uma chamada que devolve saída do modelo. O analisador associa a variável a que foi atribuída, e é isso que lhe permite seguir o valor ao longo da função sem análise interprocedimental.
Fluxo
answer contém texto influenciado por um atacante. Entre a chamada e o destino nada o inspeciona, nada o restringe e nada o reduz a um conjunto fixo de operações.
Destino
exec(…) — o texto torna-se um programa no próprio processo da aplicação, com as suas credenciais, a sua rede e o seu sistema de ficheiros.
Porque é que isto importa
Tudo o que puder influenciar task — diretamente, ou através de um documento mostrado ao modelo — escolhe o que é executado. Isto é execução remota de código com mais um salto.

Executado no motor atual, esse excerto produz um resultado: llm-output-to-code-execution, CWE-94, severidade crítica, confiança alta, na linha exec. A confiança é alta porque a variável está ligada a uma verdadeira chamada de completamento. Um nome que apenas se parece com uma resposta do modelo — llm_response, reply — é reportado com confiança média, porque isso é uma suposição e afirmar o contrário seria mentir sobre a evidência.

O que isto não é

Não é um teste ao modelo
Não sondamos o modelo, não lhe fazemos red teaming nem avaliamos como se comporta sob pressão. Nada aqui diz se um prompt pode ser contornado por jailbreak: isso não é decidível a partir do código-fonte, e afirmá-lo seria exatamente o tipo de declaração que este motor existe para evitar.
Não é deteção completa de prompt injection
A injeção indireta é reportada onde conteúdo não fiável chega comprovadamente a um prompt. Um canal que não conseguimos ver no código é um canal que não reportamos.
Não é uma garantia sobre um agente
Reportamos que foi concedida a um agente uma ferramenta que executa código ou comandos. O que o agente faz depois, em execução, está fora daquilo que a análise estática pode decidir.
Complementar à segurança de IA em execução
As guardrails, os bancos de avaliação e o red teaming respondem a perguntas a que isto não consegue responder, e isto responde a perguntas a que eles não conseguem. Nenhum substitui o outro.

Outros riscos específicos de LLM no código

Cada um foi acionado numa amostra contra o motor atual antes de ser escrito aqui.

Segredos e dados pessoais interpolados num prompt — CWE-200
Uma api_key, uma palavra-passe, um IBAN ou um registo clínico colocados no texto que envia. Reportado onde está realmente a ser construído um contexto de prompt, não em qualquer f-string que por acaso contenha uma chave.
Um agente a quem foi dada uma ferramenta que executa código ou comandos — CWE-250
PythonREPLTool, ShellTool, um interpretador de código, um terminal. Conceder uma delas transforma qualquer questão de prompt injection numa questão de execução remota de código.
Uma salvaguarda do framework novamente desativada — CWE-502
allow_dangerous_deserialization=True, trust_remote_code=True, dangerouslyAllow… — um framework desativou-a porque não era segura.
Controlos de segurança do fornecedor desativados — CWE-693
BLOCK_NONE, safety_settings=None, moderation=false.
Um prompt ou uma definição de agente obtidos em tempo de execução — CWE-829
hub.pull(…), um modelo de prompt carregado por HTTP. Quem controla esse endpoint controla as instruções.
Conteúdo não fiável carregado diretamente num prompt — CWE-77
Uma página extraída da web, um PDF, um repositório, um wiki. Este é o canal de injeção indireta, reconhecido pela proveniência do texto e não pelo que ele diz.
Uma chave de API de modelo escrita no código-fonte — CWE-798
sk-…, sk-ant-…, AIza…, hf_… submetidos ao repositório.
Um modelo retirado ou substituído fixado no código — CWE-1104
text-davinci-*, gpt-4-0314, claude-instant — hierarquia de instruções mais fraca, sem separação do prompt de sistema.

Porque deve acreditar em alguma coisa disto

Um benchmark publicado
Precisão, abrangência e F1 por CWE, por linguagem e por camada de análise, sobre um corpus versionado e anotado à mão. Ver os números.
Um perímetro publicado
Cada camada que não medimos está nomeada, com a razão. Ler a metodologia.
Validação em código público
Repositórios e commits analisados, linguagens encontradas, taxa de conclusão e determinismo — volumes e taxas, não afirmações de exatidão. Ver as execuções.
Cada resultado traz a sua evidência
O ficheiro, a linha, a construção detetada e o CWE. Um resultado que não consegue verificar é um resultado sobre o qual não deve agir.

Independente do fornecedor por construção. O analisador reconhece a forma — algo produz texto, algo consome-o — em vez da escrita de um SDK em particular. Nomeia o framework que viu quando consegue (OpenAI, Anthropic, Google, Azure OpenAI, Mistral, Bedrock, Ollama, LiteLLM, LangChain, LangGraph, LlamaIndex, Semantic Kernel, AutoGen, CrewAI, Hugging Face) para que um resultado possa dizer de onde veio. Isso é uma etiqueta no resultado, não uma integração por SDK, e um framework ausente dessa lista é analisado exatamente da mesma maneira.

Veja o Cybseco a raciocinar sobre um sistema real

Veja a demo interativa e depois solicite uma avaliação guiada para a sua equipa.