Mentalidade de Segurança para Vibe Coding com o Cursor

O vibe coding com o Cursor é rápido e divertido: você descreve o que quer, o agente escreve o código, e você mantém o fluxo sem parar para ler cada linha. O problema é que um modelo treinado para satisfazer prompts vai alegremente produzir código que funciona e parece limpo, ainda carregando injeção de SQL, chaves de API codificadas diretamente ou uma verificação de autorização que confia no cliente. Este guia dá a você uma mentalidade de segurança repetível para o fluxo de trabalho de vibe coding no Cursor, desde detectar as falhas que o código gerado por IA produz com mais frequência até auditar a saída, aplicar regras, lidar com segredos e executar uma checklist pré-implantação antes que qualquer coisa seja entregue.
O Que É Vibe Coding e Por Que a Segurança Importa
Vibe coding significa que você conduz com intenção e deixa o modelo preencher os detalhes de implementação. Você pede "um endpoint de login com um cookie de sessão" e o Cursor escreve a rota, a chamada ao banco de dados e o middleware. A saída geralmente é funcional, mas funcional não é o mesmo que seguro. O modelo otimiza para fazer o código rodar, não para se defender de um atacante que lê o mesmo código.
A segurança importa mais neste fluxo de trabalho, não menos, por três motivos:
- Você revisa menos. Quando o modelo escreve dezenas de linhas por prompt, a etapa de revisão humana se torna o gargalo e acaba sendo pulada.
- O modelo aprendeu com código inseguro. Repositórios públicos contêm bastante SQL concatenado em strings e armazenamento de tokens no lado do cliente, então esses padrões aparecem nas completions.
- O raio de impacto é grande. O modo Agent pode tocar muitos arquivos de uma vez, então um único padrão inseguro é duplicado por toda a base de código.
A segurança não é uma fase separada que você acrescenta no final. É um hábito constante que você incorpora à forma como você escreve prompts, revisa e implanta com o Cursor.
O agente do Cursor pode escrever código que compila, passa nos seus testes e ainda entrega uma vulnerabilidade. O modelo não pode assumir a responsabilidade pelo seu risco. Trate cada bloco gerado como um rascunho de um desenvolvedor júnior rápido, mas descuidado.
As Vulnerabilidades Mais Comuns em Código Gerado por IA
Estes são os modos de falha que aparecem repetidamente em código gerado por IA. Aprenda a reconhecer a forma de cada um para poder detectá-lo ao escanear, em vez de ler cada linha.
| Vulnerabilidade | Como ela aparece no código gerado | Por que o modelo a produz |
|---|---|---|
| Injeção de SQL | Consulta construída com concatenação de strings em vez de parâmetros | A concatenação é mais simples de escrever e lê "naturalmente" |
| XSS | Entrada de usuário não sanitizada renderizada com innerHTML ou dangerouslySetInnerHTML | Renderizar HTML diretamente é o caminho mais curto para o resultado visual |
| Segredos/chaves de API codificados diretamente | const API_KEY = "sk-live-..." deixado no arquivo de código-fonte | Um valor literal torna o trecho autossuficiente e executável |
| Autenticação/sessão quebrada | Tokens armazenados em localStorage, sem expiração, sem validação no lado do servidor | O armazenamento no cliente é o mais fácil de demonstrar em um navegador |
| CORS permissivo | Access-Control-Allow-Origin: * com credenciais | O curinga é a correção de uma linha que interrompe o erro imediato |
| Desserialização insegura | pickle.loads, eval, ou confiar JSON direto em objetos | Desserializar tudo é conveniente e presume entrada confiável |
| Endpoints de administração expostos | Rotas como /admin/users sem verificação de papel | O modelo implementa o recurso, mas esquece a proteção |
| Validação de entrada ausente | Corpo usado diretamente na lógica sem verificação de esquema | A validação parece redundante quando o caminho feliz já funciona |
Injeção de SQL em JavaScript
Aqui está o par clássico: uma consulta que concatena a entrada do usuário, e a mesma consulta escrita com placeholders parametrizados.
// VULNERABLE: user input is concatenated straight into the query
app.get('/user', async (req, res) => {
const sql = "SELECT * FROM users WHERE email = '" + req.query.email + "'";
const rows = await db.query(sql);
res.json(rows);
});
// FIXED: parameterized query, input never becomes part of the SQL string
app.get('/user', async (req, res) => {
const sql = 'SELECT * FROM users WHERE email = $1';
const rows = await db.query(sql, [req.query.email]);
res.json(rows);
});
Verificações de Autorização em Python
A versão vulnerável confia em uma flag enviada pelo cliente. A versão corrigida verifica a sessão autenticada no servidor.
# VULNERABLE: the client tells the server whether it is an admin
@app.get("/admin/users")
def admin_users(request):
if request.args.get("is_admin") == "true":
return db.list_users()
return {"error": "forbidden"}
# FIXED: the server decides based on the authenticated session
@app.get("/admin/users")
def admin_users(request):
user = request.session.get("user")
if not user or user["role"] != "admin":
abort(403)
return db.list_users()
Armazenamento de Token: localStorage vs Cookie httpOnly
Armazenar um token de sessão em localStorage o torna legível por qualquer script na página, o que transforma um único bug de XSS em tomada de conta completa.
// VULNERABLE: token readable by any script, no protection against XSS
localStorage.setItem('token', response.token);
// FIXED: server sets an httpOnly cookie that scripts cannot read
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 1000 * 60 * 60,
});
Auditando Código Gerado por IA com o Cursor
Auditar não significa ler cada linha. Significa pedir uma segunda passada do modelo para atacar o que a primeira passada escreveu. O Cursor é bom nisso quando você lhe dá a persona certa e um alvo claro.