O Codex e o Claude Code perderam 9 em cada 10 bugs reais em 200 casos de teste. A configuração de SAST com IA mais forte detectou 72% a um custo menor por vulnerabilidade encontrada. Testamos cinco configurações de IA em relação aos mesmos 200 trechos de código — 100 vulnerabilidades reais e 100 iscas que parecem arriscadas, mas não são.
Três rodaram o SAST com IA da Fluid Attacks em três modelos diferentes. Os outros dois eram agentes de codificação de propósito geral, Codex e Claude Code, que receberam um prompt detalhado de auditoria de segurança.
A lição mais clara: o sistema ao redor do modelo importou mais do que o próprio modelo. Os agentes de codificação foram quase impecáveis na precisão — quase nenhum alarme falso —, mas quase cegos na cobertura, perdendo mais de 9 em cada 10 vulnerabilidades reais. O SAST com IA (gpt-5-mini) trocou um pouco dessa precisão por muito mais cobertura, detectando 72% das vulnerabilidades reais a $16,92 por descoberta — menos do que qualquer outra configuração testada.
Agente de programação vs scanner de segurança de IA: o que queríamos saber
Os assistentes de programação de IA e os scanners de segurança de IA continuam sendo colocados no mesmo saco, especialmente porque ambos são apresentados como formas de detectar vulnerabilidades em código real. Eles não são o mesmo tipo de ferramenta, por isso queríamos uma resposta direta: qual a diferença de desempenho deles nos mesmos alvos? Avaliamos cinco configurações quanto à precisão, recall e F1, utilizando iscas criadas para gerar falsos positivos reais — e não apenas um número de "encontrou, sim ou não".
Metodologia
Cada ferramenta foi exposta ao mesmo conjunto de dados:
52 bases de código, 68 versões, cerca de 98 milhões de linhas de código no total.
200 trechos de código: 100 vulnerabilidades reais, 100 iscas que parecem vulneráveis, mas não são.
Dois tipos de vulnerabilidade, divididos igualmente: injeção de SQL e cross-site scripting (XSS) — duas das formas mais comuns que atacantes usam para explorar código inseguro.
Três configurações executam o AI SAST da Fluid Attacks — o mesmo pipeline, trocando o modelo subjacente a cada vez: gpt-5-mini, GPT-5.5 e Opus 4.8. As outras duas são agentes de programação que receberam a mesma instrução de auditoria: Codex no GPT-5.5, Claude Code no Claude Opus 4.7.
O AI SAST não é o modelo. É um pipeline fixo que extrai o código, sinaliza candidatos e rastreia o fluxo de dados. Um sistema de agentes, trabalhando de forma coordenada, julga quais caminhos sinalizados são de fato exploráveis, de modo que a troca do modelo subjacente altera apenas essa etapa. (Pipeline completo aqui.) Esse design possibilita dois experimentos naturais, já que o Codex e o Claude Code rodam em modelos quase idênticos a duas das três configurações do AI SAST.
Ambos os agentes receberam uma única instrução para uma auditoria completa da base de código — reproduzida integralmente abaixo, para que não haja dúvidas se eles tiveram uma chance real:
You are auditing the codebase rooted at the current working directory fortwo specific vulnerability classes:1.SQL Injection -> subcategory="SQL Injection"2.Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"You have full sandbox access. Useshell commands(grep,find,ls,cat),read files,take notes,reasonas much as you need. Thereis no turn limit.
Recommendedapproach—-----
1.Identify the language(s)and framework(s)used by thisrepo(look atmanifest files:package.json,pom.xml,requirements.txt,Gemfile,composer.json,go.mod,Cargo.toml,build.gradle,pyproject.toml).
2.Enumerate the typical SQL and XSS sinks forthat stack. Examples:
Python:cursor.execute(f"..."),Django .raw(), .extra(where=...),Jinja2 |safe,mark_safe(),format_html
Java:Statement.execute(...),createQuery/createNativeQuery withstring concatenation,JSP <%= ... %>,response.getWriter().printJS/TS:knex.raw(...),pg/mysql query templates,res.send/res.writewithunescaped input,innerHTML/dangerouslySetInnerHTML
Ruby:ActiveRecord find_by_sql / where("..."+x),html_safe,raw(),<%== %> (Slim/ERB unescaped)
PHP: mysql_query("... $..."), echo $_GET[...], unescaped Twig
Go: db.Query/Exec with fmt.Sprintf, html/template vs text/template
3. For each candidate sink, trace data flow BACKWARD to a user-controlled
source (HTTP params, query string, request body, headers, cookies, file
uploads). A finding requires BOTH a vulnerable sink AND a reachable
user-controlled source. Otherwise it's not a vulnerability.
4. Ignore other classes (NoSQL injection, command injection, SSRF, weak
crypto, deserialization, path traversal, auth flaws, etc.). Even if you
spot them, do not include them in your output.
Output
—---
When your audit is complete, WRITE your findings to a file named
`{SCANNER_OUTPUT_FILENAME}` at the working-directory root. The file must
contain a single JSON object:
{"findings": [
{"path": "<repo-relativepath>",
"line_start": <int>,
"line_end": <int|null>,
"subcategory": "SQL Injection" | "Cross-Site Scripting",
"severity": "low" | "medium" | "high" | "critical",
"message": "<one-sentencejustification>"
}
],
"summary": "<paragraphdescribingwhatyouauditedandyourconfidence>",
"scanner_self_confidence": "low" | "medium" | "high"
}
Example finding object:
{"path": "src/users/views.py", "line_start": 42, "line_end": 44,
"subcategory": "SQL Injection", "severity": "high",
"message": "User-controlled `username` from request.GET is interpolated
into raw SQL via cursor.execute(f\"SELECT...\"); attacker
can break out of the string."}
If you find no SQL Injection / Cross-Site Scripting vulnerabilities, still
write the file with an empty findings list:
{"findings": [], "summary": "...why...",
"scanner_self_confidence": "high"}
The subcategory field MUST be exactly "SQL Injection" or "Cross-Site Scripting";
any other value will be discarded. Paths must be relative to the working
directory.
Your stdout (reasoning, shell-command output, anything else) is informational
and will be ignored. Only the contents of `{SCANNER_OUTPUT_FILENAME}
You are auditing the codebase rooted at the current working directory fortwo specific vulnerability classes:1.SQL Injection -> subcategory="SQL Injection"2.Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"You have full sandbox access. Useshell commands(grep,find,ls,cat),read files,take notes,reasonas much as you need. Thereis no turn limit.
Recommendedapproach—-----
1.Identify the language(s)and framework(s)used by thisrepo(look atmanifest files:package.json,pom.xml,requirements.txt,Gemfile,composer.json,go.mod,Cargo.toml,build.gradle,pyproject.toml).
2.Enumerate the typical SQL and XSS sinks forthat stack. Examples:
Python:cursor.execute(f"..."),Django .raw(), .extra(where=...),Jinja2 |safe,mark_safe(),format_html
Java:Statement.execute(...),createQuery/createNativeQuery withstring concatenation,JSP <%= ... %>,response.getWriter().printJS/TS:knex.raw(...),pg/mysql query templates,res.send/res.writewithunescaped input,innerHTML/dangerouslySetInnerHTML
Ruby:ActiveRecord find_by_sql / where("..."+x),html_safe,raw(),<%== %> (Slim/ERB unescaped)
PHP: mysql_query("... $..."), echo $_GET[...], unescaped Twig
Go: db.Query/Exec with fmt.Sprintf, html/template vs text/template
3. For each candidate sink, trace data flow BACKWARD to a user-controlled
source (HTTP params, query string, request body, headers, cookies, file
uploads). A finding requires BOTH a vulnerable sink AND a reachable
user-controlled source. Otherwise it's not a vulnerability.
4. Ignore other classes (NoSQL injection, command injection, SSRF, weak
crypto, deserialization, path traversal, auth flaws, etc.). Even if you
spot them, do not include them in your output.
Output
—---
When your audit is complete, WRITE your findings to a file named
`{SCANNER_OUTPUT_FILENAME}` at the working-directory root. The file must
contain a single JSON object:
{"findings": [
{"path": "<repo-relativepath>",
"line_start": <int>,
"line_end": <int|null>,
"subcategory": "SQL Injection" | "Cross-Site Scripting",
"severity": "low" | "medium" | "high" | "critical",
"message": "<one-sentencejustification>"
}
],
"summary": "<paragraphdescribingwhatyouauditedandyourconfidence>",
"scanner_self_confidence": "low" | "medium" | "high"
}
Example finding object:
{"path": "src/users/views.py", "line_start": 42, "line_end": 44,
"subcategory": "SQL Injection", "severity": "high",
"message": "User-controlled `username` from request.GET is interpolated
into raw SQL via cursor.execute(f\"SELECT...\"); attacker
can break out of the string."}
If you find no SQL Injection / Cross-Site Scripting vulnerabilities, still
write the file with an empty findings list:
{"findings": [], "summary": "...why...",
"scanner_self_confidence": "high"}
The subcategory field MUST be exactly "SQL Injection" or "Cross-Site Scripting";
any other value will be discarded. Paths must be relative to the working
directory.
Your stdout (reasoning, shell-command output, anything else) is informational
and will be ignored. Only the contents of `{SCANNER_OUTPUT_FILENAME}
You are auditing the codebase rooted at the current working directory fortwo specific vulnerability classes:1.SQL Injection -> subcategory="SQL Injection"2.Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"You have full sandbox access. Useshell commands(grep,find,ls,cat),read files,take notes,reasonas much as you need. Thereis no turn limit.
Recommendedapproach—-----
1.Identify the language(s)and framework(s)used by thisrepo(look atmanifest files:package.json,pom.xml,requirements.txt,Gemfile,composer.json,go.mod,Cargo.toml,build.gradle,pyproject.toml).
2.Enumerate the typical SQL and XSS sinks forthat stack. Examples:
Python:cursor.execute(f"..."),Django .raw(), .extra(where=...),Jinja2 |safe,mark_safe(),format_html
Java:Statement.execute(...),createQuery/createNativeQuery withstring concatenation,JSP <%= ... %>,response.getWriter().printJS/TS:knex.raw(...),pg/mysql query templates,res.send/res.writewithunescaped input,innerHTML/dangerouslySetInnerHTML
Ruby:ActiveRecord find_by_sql / where("..."+x),html_safe,raw(),<%== %> (Slim/ERB unescaped)
PHP: mysql_query("... $..."), echo $_GET[...], unescaped Twig
Go: db.Query/Exec with fmt.Sprintf, html/template vs text/template
3. For each candidate sink, trace data flow BACKWARD to a user-controlled
source (HTTP params, query string, request body, headers, cookies, file
uploads). A finding requires BOTH a vulnerable sink AND a reachable
user-controlled source. Otherwise it's not a vulnerability.
4. Ignore other classes (NoSQL injection, command injection, SSRF, weak
crypto, deserialization, path traversal, auth flaws, etc.). Even if you
spot them, do not include them in your output.
Output
—---
When your audit is complete, WRITE your findings to a file named
`{SCANNER_OUTPUT_FILENAME}` at the working-directory root. The file must
contain a single JSON object:
{"findings": [
{"path": "<repo-relativepath>",
"line_start": <int>,
"line_end": <int|null>,
"subcategory": "SQL Injection" | "Cross-Site Scripting",
"severity": "low" | "medium" | "high" | "critical",
"message": "<one-sentencejustification>"
}
],
"summary": "<paragraphdescribingwhatyouauditedandyourconfidence>",
"scanner_self_confidence": "low" | "medium" | "high"
}
Example finding object:
{"path": "src/users/views.py", "line_start": 42, "line_end": 44,
"subcategory": "SQL Injection", "severity": "high",
"message": "User-controlled `username` from request.GET is interpolated
into raw SQL via cursor.execute(f\"SELECT...\"); attacker
can break out of the string."}
If you find no SQL Injection / Cross-Site Scripting vulnerabilities, still
write the file with an empty findings list:
{"findings": [], "summary": "...why...",
"scanner_self_confidence": "high"}
The subcategory field MUST be exactly "SQL Injection" or "Cross-Site Scripting";
any other value will be discarded. Paths must be relative to the working
directory.
Your stdout (reasoning, shell-command output, anything else) is informational
and will be ignored. Only the contents of `{SCANNER_OUTPUT_FILENAME}
You are auditing the codebase rooted at the current working directory fortwo specific vulnerability classes:1.SQL Injection -> subcategory="SQL Injection"2.Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"You have full sandbox access. Useshell commands(grep,find,ls,cat),read files,take notes,reasonas much as you need. Thereis no turn limit.
Recommendedapproach—-----
1.Identify the language(s)and framework(s)used by thisrepo(look atmanifest files:package.json,pom.xml,requirements.txt,Gemfile,composer.json,go.mod,Cargo.toml,build.gradle,pyproject.toml).
2.Enumerate the typical SQL and XSS sinks forthat stack. Examples:
Python:cursor.execute(f"..."),Django .raw(), .extra(where=...),Jinja2 |safe,mark_safe(),format_html
Java:Statement.execute(...),createQuery/createNativeQuery withstring concatenation,JSP <%= ... %>,response.getWriter().printJS/TS:knex.raw(...),pg/mysql query templates,res.send/res.writewithunescaped input,innerHTML/dangerouslySetInnerHTML
Ruby:ActiveRecord find_by_sql / where("..."+x),html_safe,raw(),<%== %> (Slim/ERB unescaped)
PHP: mysql_query("... $..."), echo $_GET[...], unescaped Twig
Go: db.Query/Exec with fmt.Sprintf, html/template vs text/template
3. For each candidate sink, trace data flow BACKWARD to a user-controlled
source (HTTP params, query string, request body, headers, cookies, file
uploads). A finding requires BOTH a vulnerable sink AND a reachable
user-controlled source. Otherwise it's not a vulnerability.
4. Ignore other classes (NoSQL injection, command injection, SSRF, weak
crypto, deserialization, path traversal, auth flaws, etc.). Even if you
spot them, do not include them in your output.
Output
—---
When your audit is complete, WRITE your findings to a file named
`{SCANNER_OUTPUT_FILENAME}` at the working-directory root. The file must
contain a single JSON object:
{"findings": [
{"path": "<repo-relativepath>",
"line_start": <int>,
"line_end": <int|null>,
"subcategory": "SQL Injection" | "Cross-Site Scripting",
"severity": "low" | "medium" | "high" | "critical",
"message": "<one-sentencejustification>"
}
],
"summary": "<paragraphdescribingwhatyouauditedandyourconfidence>",
"scanner_self_confidence": "low" | "medium" | "high"
}
Example finding object:
{"path": "src/users/views.py", "line_start": 42, "line_end": 44,
"subcategory": "SQL Injection", "severity": "high",
"message": "User-controlled `username` from request.GET is interpolated
into raw SQL via cursor.execute(f\"SELECT...\"); attacker
can break out of the string."}
If you find no SQL Injection / Cross-Site Scripting vulnerabilities, still
write the file with an empty findings list:
{"findings": [], "summary": "...why...",
"scanner_self_confidence": "high"}
The subcategory field MUST be exactly "SQL Injection" or "Cross-Site Scripting";
any other value will be discarded. Paths must be relative to the working
directory.
Your stdout (reasoning, shell-command output, anything else) is informational
and will be ignored. Only the contents of `{SCANNER_OUTPUT_FILENAME}
A comparação mantém-se íntegra por quatro motivos. Os bugs são CVEs públicos no código de terceiros. Nada foi ajustado para este conjunto de dados. O escopo foi definido antes do início de qualquer verificação. E um acerto só conta se a ferramenta identificar o arquivo, a função e o tipo de vulnerabilidade corretos.
Resultados
A tabela abaixo avalia as cinco configurações — as três configurações de AI SAST da Fluid Attacks e os dois agentes de programação — em relação ao mesmo benchmark.
Métrica
AI SAST (gpt-5-mini)
Codex
Claude Code
AI SAST (5.5)
AI SAST (Opus 4.8)
Verdadeiros positivos
72
9
8
19
47
Falsos positivos
66
2
0
14
30
Verdadeiros negativos
34
98
100
86
70
Falsos negativos
28
91
92
81
53
Recall
0,72
0,09
0,08
0,19
0,47
Precisão
0,52
0,82
1
0,58
0,61
F0,5 (ponderado pela precisão)
0,55
0,31
0,3
0,41
0,58
Pontuação F1
0,61
0,16
0,15
0,29
0,53
F2 (ponderado pelo recall)
0,67
0,11
0,1
0,22
0,49
Especificidade
0,34
0,98
1
0,86
0,7
FPR
0,66
0,02
0
0,14
0,3
Acurácia
0,53
0,535
0,54
0,525
0,585
Custo total
$1.218
$359
$554
$4.689*
$4.264*
Custo por vuln encontrada
$16,92
$39,92
$69,21
$246,80*
$90,72*
Tempo de execução (min)
85,4
5,1
15,5
n/a
n/a
*Custo estimado, projetado a partir de uma execução direcionada; verificado com margem de erro de aproximadamente 1% em relação a uma linha de base medida.
Precisão e recall caminharam em direções opostas. O Claude Code nunca gerou um alarme falso — precisão de 1,00 — mas deixou passar 92 das 100 vulnerabilidades reais; o Codex deixou passar 91, apesar da precisão de 0,82. O AI SAST (gpt-5-mini) detectou 72 de 100, mais do que qualquer outra configuração, mas foi enganado por 66 das 100 iscas, resultando em uma precisão de 0,52. Um extremo oferece alarmes quase perfeitos ao custo de uma cegueira quase total; o outro, cobertura ampla com uma carga maior de revisão.
A acurácia esconde mais do que revela aqui, porque o conjunto de dados é equilibrado em 50/50. Cada ferramenta ficou entre 0,525 e 0,585 — fazendo com que as cinco parecessem intercambiáveis, o que não são. Uma ferramenta que classifica quase tudo como "não é vulnerabilidade" atinge cerca de 0,5 por padrão, próximo ao Codex e Claude Code. O F1 separa os concorrentes de forma mais honesta: 0,61 para o gpt-5-mini e 0,53 para o Opus 4.8, contra apenas 0,15–0,16 para os agentes de programação.
Gastar mais não garantiu uma detecção melhor. O AI SAST (gpt-5-mini) foi o mais barato e eficaz, a $16,92 por vulnerabilidade real encontrada. O AI SAST (GPT-5.5), um modelo mais caro no mesmo sistema, custou um valor estimado de $246,80 por vulnerabilidade — quatorze vezes mais — apresentando desempenho inferior em recall e F1.
O cross-site scripting foi quase um ponto cego total para os agentes de programação: de 50 casos reais de XSS, o Claude Code não encontrou nenhum e o Codex encontrou apenas 2; o AI SAST (GPT-5.5) detectou apenas 3. Somente o gpt-5-mini (40 de 50) e o Opus 4.8 (21 of 50) lidaram com XSS de forma significativa — prova de que um número alto de recall pode mascarar uma falha quase total em um tipo de vulnerabilidade.
O sistema, e não o modelo, impulsionou a detecção
O Claude Code e o AI SAST (Opus 4.8) rodam quase no mesmo modelo. Sozinho, ele encontrou 8 de 100 vulnerabilidades reais; dentro do AI SAST, encontrou 47 — um ganho de 5,9x (p < 10⁻⁹). A dupla com GPT-5.5 mostra o mesmo cenário: o Codex sozinho encontrou 9 de 100; o AI SAST (GPT-5.5) encontrou 19 — um ganho de 2,1x (p ≈ 0,04).
Já havíamos chegado a uma conclusão semelhante anteriormente ao analisar o Claude Code isoladamente: os resultados estão associados à engenharia em torno do modelo, e não ao modelo em si. Este benchmark aponta na mesma direção: o gpt-5-mini, o menor e mais barato modelo, venceu em recall e F1, à frente de ambos os modelos maiores.
Principais conclusões
A escolha entre essas ferramentas se resume a qual tipo de falha sua equipe está disposta a aceitar. Os agentes de programação focados em precisão quase nunca dão falsos alarmes, mas deixam passar a maioria dos problemas reais, o que os torna limitados como scanner principal. Equipes que desejam um assistente de programação com contexto de segurança integrado são melhor atendidas por uma ferramenta desenvolvida para essa função, como o AI Code Security Assistance. Se deixar passar uma vulnerabilidade for o maior risco, as configurações de AI SAST com maior recall revelam muito mais vulnerabilidades reais, e o AI SAST com gpt-5-mini da Fluid Attacks faz isso de forma mais barata, porém com uma fila de revisão maior.
Uma ferramenta que não encontra quase nada não parece quebrada, ela parece reconfortante. O Claude Code deixou passar 92 de 100 vulnerabilidades reais aqui e ainda entregou um relatório limpo, com zero alarmes falsos para justificar. Esse é o custo real de um scanner com recall quase nulo: não os resultados que ele erra, mas aqueles que ele nunca menciona. Independentemente de qual perfil se ajusta à sua tolerância ao risco, teste-o e governe-o primeiro.
Uma nota final: a execução que optou por não participar
Uma configuração nunca chegou aos resultados finais: Claude Code no Fable 5. O Fable 5 recusou sumariamente a tarefa de cibersegurança e repassou o trabalho para o Opus 4.8. Sem nada para avaliar, nós o deixamos de fora — um lembrete de que a disposição de um modelo para tentar uma tarefa é em si uma variável, que antecede a precisão e o recall.
Quer ver como o AI SAST se comporta no seu próprio código? Explore a Segurança de IA ou veja como os resultados passam da sinalização à correção na nossa plataforma.
As soluções da Fluid Attacks permitem que as organizações identifiquem, priorizem e corrijam vulnerabilidades em seus softwares ao longo do SDLC. Com o apoio de IA, ferramentas automatizadas e pentesters, a Fluid Attacks acelera a mitigação da exposição ao risco das empresas e fortalece sua postura de cibersegurança.
As soluções da Fluid Attacks permitem que as organizações identifiquem, priorizem e corrijam vulnerabilidades em seus softwares ao longo do SDLC. Com o apoio de IA, ferramentas automatizadas e pentesters, a Fluid Attacks acelera a mitigação da exposição ao risco das empresas e fortalece sua postura de cibersegurança.
As soluções da Fluid Attacks permitem que as organizações identifiquem, priorizem e corrijam vulnerabilidades em seus softwares ao longo do SDLC. Com o apoio de IA, ferramentas automatizadas e pentesters, a Fluid Attacks acelera a mitigação da exposição ao risco das empresas e fortalece sua postura de cibersegurança.