{
  "id": "ai-writes-insecure-sql",
  "type": "failures",
  "category": "failures",
  "locale": "pt",
  "url": "/pt/failures/ai-writes-insecure-sql",
  "title": "Como Corrigir SQL Inseguro Escrito por IA",
  "description": "Agentes de IA criam consultas SQL com interpolação de strings em vez de instruções parametrizadas, introduzindo vulnerabilidades de injeção SQL no código de banco de dados em produção.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "PostgreSQL",
    "TypeScript"
  ],
  "tags": [
    "sql",
    "security",
    "postgres"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "O agente recorre a literais de modelo para construir consultas SQL, criando vetores clássicos de injeção SQL que parecem funcionar bem em testes, mas são exploráveis em produção.\n\n## O sintoma\n\nValores controlados pelo usuário são interpolados diretamente em uma string SQL.\n\n```ts\n// WRONG — SQL injection vulnerability\nasync function getUserByEmail(email: string) {\n  const result = await db.query(\n    `SELECT * FROM users WHERE email = '${email}'`\n    //                                  ^^^^^^^ attacker-controlled\n  );\n  return result.rows[0];\n}\n\n// Attacker input: ' OR '1'='1\n// Resulting query: SELECT * FROM users WHERE email = '' OR '1'='1'\n// Returns every row in the table.\n```\n\n## Por que isso acontece\n\nLiterais de modelo são a ferramenta mais natural para construir strings em JavaScript, e muitos exemplos de tutoriais com os quais o modelo foi treinado os utilizam para SQL sem parametrização. O agente também não modela entradas adversárias — ele imagina dados bem formados passando.\n\n## Como identificar\n\n- Strings SQL que contêm interpolações `${...}`.\n- Funções de consulta que aceitam entrada do usuário e a passam para um auxiliar de consulta bruta sem um array de parâmetros separado.\n- `db.query(sql)` chamado com um único argumento em vez de `db.query(sql, [params])`.\n- Padrões `LIKE '%${term}%'`.\n\n## Como corrigir\n\nSempre use consultas parametrizadas. O driver do banco de dados lida com o escape; seu código nunca toca em citações.\n\n```ts\n// CORRECT — parameterized query (node-postgres / pg)\nasync function getUserByEmail(email: string) {\n  const result = await db.query(\n    \"SELECT id, name, email FROM users WHERE email = $1\",\n    [email]  // second argument: params array\n  );\n  return result.rows[0] ?? null;\n}\n\n// CORRECT — with Postgres.js (template tag)\nasync function searchUsers(term: string) {\n  return sql`SELECT id, name FROM users WHERE name ILIKE ${\"%\" + term + \"%\"}`;\n  // postgres.js automatically parameterizes template expressions\n}\n```\n\n```txt\n[ ] No ${...} inside raw SQL strings — use $1/$2 placeholders instead\n[ ] Every db.query() call passes user input via the params array, not the SQL string\n[ ] Use an ORM (Prisma, Drizzle) or query builder for complex queries\n[ ] LIKE wildcards are appended in the param value, not concatenated into the SQL\n[ ] Run sqlfluff or a SQL linter in CI to catch interpolated strings\n```\n\n## Prompt de Correção\n\n```txt title=\"Fix Prompt\"\nThis SQL query uses string interpolation with user-supplied values, which is a\nSQL injection vulnerability. Rewrite every raw query to use parameterized\nstatements ($1, $2 placeholders for pg, or the tagged template literal form for\npostgres.js). Never interpolate variables directly into SQL strings. If the\nquery is complex, migrate it to Prisma or Drizzle ORM instead.\n```\n\n## Teste\n\n```bash\n# Detect template literal interpolation inside SQL-looking strings\ngrep -rn 'query(`\\|sql`\\|execute(`' --include=\"*.ts\" --include=\"*.tsx\" . \\\n  | grep '\\${' \\\n  | grep -v \"node_modules\" \\\n  && echo \"FAIL: interpolated SQL found\" || echo \"OK\"\n```"
}