Seguridad en código IA

SQL Injection 101 - Por qué tu app Lovable puede estar expuesta

23 de febrero de 2026
Vibe2Prod
7 min

SQL Injection es el ataque más viejo de internet y sigue siendo el más efectivo. Si usaste Lovable o Cursor para generar tu backend, es probable que tengas al menos un punto vulnerable. Aquí te explico cómo detectarlo y corregirlo.

SQL Injection es probablemente el ataque más viejo de internet.

Pero sigue siendo el más efectivo. Y si usaste Lovable o Cursor para generar tu backend, tienes riesgo.


¿Qué es SQL Injection?

Es cuando un atacante introduce código SQL malicioso a través de un campo de entrada para manipular tu base de datos.

Ejemplo básico:

Tu app tiene un login. Espera un email y contraseña:

const email = 'user@example.com';
const password = 'abc123';

const query = `SELECT * FROM users WHERE email = '${email}' AND password = '${password}'`;

Normal, ¿verdad?

Ahora un atacante entra este email:

user@example.com' OR '1'='1

La query se convierte en:

SELECT * FROM users WHERE email = 'user@example.com' OR '1'='1' AND password = 'abc123'

La condición '1'='1' siempre es verdadera. Devuelve el primer usuario de la tabla. Generalmente el admin.

El atacante ni siquiera necesita contraseña.


Por qué Lovable (y Cursor) generan código vulnerable

Porque cuando generas rápido, tiendes a hacer esto:

app.get('/api/users/:id', async (req, res) => {
  const userId = req.params.id;
  const query = `SELECT * FROM users WHERE id = ${userId}`;
  const result = await db.query(query);
  res.json(result);
});

Parece inofensivo. Pero si alguien pasa:

/api/users/1 OR 1=1

La query se convierte en:

SELECT * FROM users WHERE id = 1 OR 1=1

Y de repente ves TODOS los usuarios, no solo el tuyo.


La solución: consultas parametrizadas

En lugar de concatenar variables directamente, usas marcadores de posición.

❌ VULNERABLE:

const query = `SELECT * FROM users WHERE id = ${userId}`;

✅ SEGURO (con driver nativo):

const query = 'SELECT * FROM users WHERE id = ?';
const result = await db.query(query, [userId]);

✅ SEGURO (con Prisma — recomendado):

const user = await prisma.user.findUnique({
  where: { id: parseInt(userId) }
});

✅ SEGURO (con TypeORM):

const user = await getRepository(User).findOne({
  where: { id: userId }
});

¿Por qué funciona? Porque el parámetro se trata como un DATO, no como código SQL.


Otros vectores de SQL Injection

1. Inyección en ORDER BY

const sortBy = req.query.sort; // El usuario pasa esto
const query = `SELECT * FROM products ORDER BY ${sortBy}`;

Atacante pasa: name; DROP TABLE products;--

Resultado: Tu tabla se borra.

Solución: Usa una lista blanca de columnas permitidas.

const allowedColumns = ['name', 'price', 'created_at'];
const sortBy = allowedColumns.includes(req.query.sort) ? req.query.sort : 'name';
const query = `SELECT * FROM products ORDER BY ${sortBy}`;

2. Inyección ciega (Blind SQL Injection)

A veces el atacante no ve el resultado directamente, pero lo puede inferir.

// La app no muestra errores, pero sí dice "usuario encontrado" o "no encontrado"
const query = `SELECT * FROM users WHERE id = ${userId}`;
if (result.length > 0) {
  res.json({ found: true });
} else {
  res.json({ found: false });
}

El atacante puede inyectar:

1 AND (SELECT COUNT(*) FROM users) > 0

Si vuelve found: true, confirma que hay usuarios en la BD. Si prueba con otras condiciones, puede extraer info del esquema entera.

Solución: Parametrización + rate limiting en todos los endpoints.

3. Inyección en LIKE

const search = req.query.q;
const query = `SELECT * FROM posts WHERE title LIKE '%${search}%'`;

Un atacante puede inyectar wildcards:

search = %' OR '1'='1

Solución: Usa parametrización y escapa los caracteres especiales.

const query = 'SELECT * FROM posts WHERE title LIKE ?';
const result = await db.query(query, [`%${search}%`]);

Checklist: ¿estás seguro?

  • [ ] ¿Todas tus queries usan parametrización o un ORM?
  • [ ] ¿Nunca concatenas variables directamente en SQL?
  • [ ] ¿Validas longitud y tipo de inputs en backend?
  • [ ] ¿Tienes listas blancas para campos dinámicos (ORDER BY, etc.)?
  • [ ] ¿Tu usuario de BD tiene permisos mínimos (no es root)?

Si respondiste "no" a cualquiera de estas, tienes riesgo.


Herramientas para detectar SQL Injection

| Herramienta | Para qué | |-------------|----------| | Burp Suite Community | Probar manualmente | | OWASP ZAP | Escaneo automático | | Snyk | Analizar dependencias | | SQLMap | Detectar SQL injection en endpoints |


Resumen

SQL Injection es fácil de prevenir si sabes cómo.

La regla de oro: Nunca concatenes entrada de usuario directamente en SQL. Usa parametrización o un ORM.

Si generaste código con Lovable/Cursor, revisa tu backend. Probablemente encuentres al menos un lugar vulnerable.

Agenda una auditoría si quieres que alguien lo revise por ti.


Referencias

[1] OWASP. (2024). SQL Injection. https://owasp.org/www-community/attacks/SQL_Injection

[2] Veracode. (2025). AI-Generated Code Security Risks. https://www.veracode.com/blog/ai-generated-code-security-risks/

[3] PortSwigger. (2024). SQL Injection Cheat Sheet. https://portswigger.net/web-security/sql-injection/cheat-sheet

¿Necesitas ayuda con tu app?

Si quieres revisar código, configuración o despliegue antes de abrir producción, vemos tu caso en una llamada de 30 minutos.

Agenda una llamada