Índice

Título
Índice
Índice
Título

Ataques

O AI SAST da Fluid Attacks superou os agentes de codificação em nosso benchmark de vulnerabilidades

cover-security-through-transparency (https://unsplash.com/photos/person-holding-black-smartphone-_IL9n-5Ou6c)
Camila Moya

Redator técnico

7 min

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 for
two specific vulnerability classes:
1. SQL Injection -> subcategory="SQL Injection"
2. Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"

You have full sandbox access. Use shell commands (grep, find, ls, cat),
read files, take notes, reason as much as you need. There is no turn limit.

Recommended approach
-----
1. Identify the language(s) and framework(s) used by this repo (look at
   manifest 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 for that stack. Examples:
     Python:  cursor.execute(f"..."), Django .raw(), .extra(where=...),
              Jinja2 |safe, mark_safe(), format_html
     Java:    Statement.execute(...), createQuery/createNativeQuery with
              string concatenation, JSP <%= ... %>, response.getWriter().print
     JS/TS:   knex.raw(...), pg/mysql query templates, res.send/res.write
              with unescaped 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-relative path>",
      "line_start":  <int>,
      "line_end":    <int|null>,
      "subcategory": "SQL Injection" | "Cross-Site Scripting",
      "severity":    "low" | "medium" | "high" | "critical",
      "message":     "<one-sentence justification>"
    }
  ],
  "summary": "<paragraph describing what you audited and your confidence>",
  "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 for
two specific vulnerability classes:
1. SQL Injection -> subcategory="SQL Injection"
2. Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"

You have full sandbox access. Use shell commands (grep, find, ls, cat),
read files, take notes, reason as much as you need. There is no turn limit.

Recommended approach
-----
1. Identify the language(s) and framework(s) used by this repo (look at
   manifest 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 for that stack. Examples:
     Python:  cursor.execute(f"..."), Django .raw(), .extra(where=...),
              Jinja2 |safe, mark_safe(), format_html
     Java:    Statement.execute(...), createQuery/createNativeQuery with
              string concatenation, JSP <%= ... %>, response.getWriter().print
     JS/TS:   knex.raw(...), pg/mysql query templates, res.send/res.write
              with unescaped 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-relative path>",
      "line_start":  <int>,
      "line_end":    <int|null>,
      "subcategory": "SQL Injection" | "Cross-Site Scripting",
      "severity":    "low" | "medium" | "high" | "critical",
      "message":     "<one-sentence justification>"
    }
  ],
  "summary": "<paragraph describing what you audited and your confidence>",
  "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 for
two specific vulnerability classes:
1. SQL Injection -> subcategory="SQL Injection"
2. Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"

You have full sandbox access. Use shell commands (grep, find, ls, cat),
read files, take notes, reason as much as you need. There is no turn limit.

Recommended approach
-----
1. Identify the language(s) and framework(s) used by this repo (look at
   manifest 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 for that stack. Examples:
     Python:  cursor.execute(f"..."), Django .raw(), .extra(where=...),
              Jinja2 |safe, mark_safe(), format_html
     Java:    Statement.execute(...), createQuery/createNativeQuery with
              string concatenation, JSP <%= ... %>, response.getWriter().print
     JS/TS:   knex.raw(...), pg/mysql query templates, res.send/res.write
              with unescaped 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-relative path>",
      "line_start":  <int>,
      "line_end":    <int|null>,
      "subcategory": "SQL Injection" | "Cross-Site Scripting",
      "severity":    "low" | "medium" | "high" | "critical",
      "message":     "<one-sentence justification>"
    }
  ],
  "summary": "<paragraph describing what you audited and your confidence>",
  "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 for
two specific vulnerability classes:
1. SQL Injection -> subcategory="SQL Injection"
2. Cross-Site Scripting / HTML injection -> subcategory="Cross-Site Scripting"

You have full sandbox access. Use shell commands (grep, find, ls, cat),
read files, take notes, reason as much as you need. There is no turn limit.

Recommended approach
-----
1. Identify the language(s) and framework(s) used by this repo (look at
   manifest 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 for that stack. Examples:
     Python:  cursor.execute(f"..."), Django .raw(), .extra(where=...),
              Jinja2 |safe, mark_safe(), format_html
     Java:    Statement.execute(...), createQuery/createNativeQuery with
              string concatenation, JSP <%= ... %>, response.getWriter().print
     JS/TS:   knex.raw(...), pg/mysql query templates, res.send/res.write
              with unescaped 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-relative path>",
      "line_start":  <int>,
      "line_end":    <int|null>,
      "subcategory": "SQL Injection" | "Cross-Site Scripting",
      "severity":    "low" | "medium" | "high" | "critical",
      "message":     "<one-sentence justification>"
    }
  ],
  "summary": "<paragraph describing what you audited and your confidence>",
  "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.

Tags:

cibersegurança

devsecops

codigo

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

Comece seu teste gratuito de 21 dias

Descubra os benefícios da solução Fluid Attacks, da qual empresas de todos os tamanhos já desfrutam.

Comece seu teste gratuito de 21 dias

Descubra os benefícios da solução Fluid Attacks, da qual empresas de todos os tamanhos já desfrutam.

Comece seu teste gratuito de 21 dias

Descubra os benefícios da solução Fluid Attacks, da qual empresas de todos os tamanhos já desfrutam.

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.

Consulta IA sobre Fluid Attacks

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

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.

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

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.

Assine nossa newsletter

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.

Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.