Claude Code security review: revisa tu diff antes del merge
La consulta tiene catorce líneas. Usa $1 para el user_id, así que a simple vista parece parametrizada. Es el tipo de código que un agente te entrega en medio minuto y que pasa por delante de tus ojos sin que lo mires dos veces.
No lo está del todo. El segundo filtro va metido con un template literal, y eso basta para que cualquier usuario autenticado lea los pedidos de todos los demás.
Ese es el fallo que el Claude Code security review busca en tu rama antes de que llegue a main. El que se cuela porque el diff es pequeño y nadie lo lee con ojos de atacante.
En corto: /security-review es un comando incluido en Claude Code que analiza el diff de tu rama contra la rama por defecto de origin y reporta solo vulnerabilidades de alta confianza: inyecciones, fallos de auth y exposición de datos. Para CI existe la GitHub Action oficial anthropics/claude-code-security-review. No sustituye al SAST, ni al escaneo de dependencias, ni al pentest.
¿Qué es /security-review en Claude Code?
/security-review es el comando de Claude Code que hace una pasada de seguridad, bajo demanda, sobre los cambios de tu rama actual. La referencia de comandos (consultada en octubre de 2026) dice que revisa el diff entre tu rama y la rama por defecto de origin, buscando inyección, problemas de auth y exposición de datos.
No lo confundas con /code-review, que busca bugs de corrección en el mismo diff. Si lo que quieres es una revisión de lógica y estilo con agentes, eso lo cuento en agentic code review con Claude Code.
El prompt de referencia es público: está en el repositorio de la Action, y su README afirma que el comando integrado ofrece el mismo análisis. Pide examinar cinco familias:
- Validación de entrada: inyección SQL, de comandos, NoSQL, de plantillas, XXE, path traversal.
- Auth: bypass de autenticación, escalada de privilegios, sesiones, JWT.
- Criptografía y secretos: claves hardcodeadas, algoritmos débiles, aleatoriedad insegura.
- Ejecución de código: deserialización insegura, pickle, YAML,
eval, XSS. - Exposición de datos: secretos o PII en logs, fugas en endpoints, debug expuesto.
Un detalle cambia cómo debes leer el resultado: el prompt solo reporta lo que tenga más de un 80 % de confianza de ser explotable, y solo lo que introduce esta rama. Lo que ya existía no aparece.
Cómo ejecutar Claude Code security review sobre tu rama
Abre Claude Code en tu repo, sitúate en la rama y escribe /security-review. En modo no interactivo: claude -p "/security-review". Añade --output-format json si quieres el coste y la duración de cada ejecución.
El comando construye su contexto con git diff --merge-base origin/HEAD. Si tu clon no tiene origin/HEAD, falla con ambiguous argument 'origin/HEAD...'. La referencia de errores documenta la solución:
git remote set-head origin main # o el nombre de tu rama por defecto
La documentación no fija versión mínima de Claude Code; la prueba de este post se hizo con la 2.1.295.
Ejemplo: la inyección SQL que detecta en un endpoint
Para este post se montó un repo de prueba con Express y pg. En main, la ruta /api/orders/:id parametriza todo. En la rama feat/filter-orders se metió a propósito este endpoint:
import type { Express } from 39;express39;;
import { pool } from 39;./db.js39;;
import { requireUser } from 39;./auth.js39;;
export function registerOrderList(app: Express) {
app.get(39;/api/orders39;, requireUser, async (req, res) => {
const status = String(req.query.status ?? 39;paid39;);
const { rows } = await pool.query(
`SELECT id, total, status FROM orders WHERE user_id = $1 AND status = '${status}'`,
[res.locals.userId]
);
res.json(rows);
});
}
Es vulnerable de verdad. Con ?status=x' OR '1'='1, la condición queda user_id = $1 AND status = 'x' OR '1'='1'. Como AND se evalúa antes que OR, es cierta para todas las filas y el endpoint devuelve los pedidos de todos los usuarios.
Sobre esa rama se ejecutó claude -p "/security-review" --output-format json. Devolvió un único hallazgo: SQL Injection en src/orders-list.ts:9, severidad High, confianza 9/10, confirmado por un subagente de filtrado de falsos positivos. Explicó el payload OR '1'='1, la vía UNION SELECT y por qué String() no protege nada.
También notó que la ruta existente en src/app.ts sí parametrizaba: compara lo nuevo con los patrones del repo.
Tardó 84 segundos y costó 0,79 USD a precio de lista con Opus 5.5, según el campo de coste de esa salida JSON (9 de octubre de 2026, una ejecución sobre un diff de 17 líneas). El arreglo es parametrizar y cerrar el valor a una lista conocida:
import { z } from 39;zod39;;
const OrderQuery = z.object({
status: z.enum([39;paid39;, 39;pending39;, 39;shipped39;, 39;cancelled39;]).default(39;paid39;),
});
app.get(39;/api/orders39;, requireUser, async (req, res) => {
const parsed = OrderQuery.safeParse(req.query);
if (!parsed.success) return res.status(400).json({ error: 39;invalid status39; });
const { rows } = await pool.query(
39;SELECT id, total, status FROM orders WHERE user_id = $1 AND status = $239;,
[res.locals.userId, parsed.data.status]
);
res.json(rows);
});
La parametrización cierra la inyección. El z.enum es la segunda defensa y hace explícito el contrato del endpoint. Si quieres trabajar ese patrón, el curso de Zod va de validar entradas en la frontera, justo donde nacen estas inyecciones.
Claude Code security review en CI con la GitHub Action
Anthropic publica anthropics/claude-code-security-review, una Action con licencia MIT que analiza el diff de cada pull request y comenta los hallazgos en las líneas afectadas. La presentó en su blog en agosto de 2025. Si quieres ver cómo encaja con el resto de revisiones automáticas del pipeline, está en cómo integrar revisiones de código con IA en CI/CD.
name: Security Review
permissions:
pull-requests: write
contents: read
on:
pull_request:
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 2
- uses: anthropics/claude-code-security-review@0c6a49f1fa56a1d472575da86a94dbc1edb78eda # main a 11-feb-2026
with:
comment-pr: true
claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
Dos avisos antes de copiarlo. El README advierte que la Action no está endurecida contra prompt injection y recomienda usarla solo con PRs de confianza. Y no uses @main: es una referencia mutable. El issue #112 pide fijarla a un SHA de 40 caracteres, como en el ejemplo, para no abrir un vector de supply chain. Fija también claude-model al modelo que uses hoy; el valor por defecto del README es Opus 4.1.
Cómo personalizar /security-review para tu proyecto
En local, el README indica que copies security-review.md del repo a .claude/commands/ y lo edites. La documentación de skills confirma que, en una sesión de terminal local, un comando de proyecto con el mismo nombre sustituye al integrado.
Lo útil de editar es el filtrado: si en tu proyecto las variables de entorno no son de confianza, o te importan los open redirects, cámbialo ahí.
En la Action tienes dos inputs que apuntan a ficheros de texto: custom-security-scan-instructions añade categorías propias (reglas de PCI DSS, de tu ORM interno) y false-positive-filtering-instructions ajusta qué se descarta. El issue #151 reporta que las rutas relativas documentadas se ignoran en silencio, y el código lee igual el fichero de filtrado. Pasa siempre la ruta absoluta: ${{ github.workspace }}/.github/security-rules.txt.
¿Qué se le escapa a Claude Code security review?
Está calibrado para hacer poco ruido, y eso tiene precio. Excluye por diseño la denegación de servicio, el rate limiting, el ReDoS, las dependencias desactualizadas y los SSRF que solo controlan el path. Asume que las variables de entorno son de confianza y que Angular y React escapan el XSS salvo con bypassSecurityTrustHtml o dangerouslySetInnerHTML.
No son errores del modelo, son decisiones del prompt. Pero si tu amenaza principal está en esa lista, un "0 hallazgos" no significa nada.
El falso negativo más peligroso es operativo. El issue #80 documenta que, con diffs de más de 20.000 líneas, la Action reporta 0 hallazgos y check en verde sin analizar nada. El issue #120 describe otro verde falso: la caché salta commits nuevos de la misma PR. Ambos seguían abiertos al escribir esto. Mientras #120 siga abierto, run-every-commit: true evita la caché a cambio de más ejecuciones y más coste.
| Criterio | /security-review |
SAST (tipo Semgrep) | Revisión humana / pentest |
|---|---|---|---|
| Qué analiza | Solo el diff de tu rama | Todo el código, con reglas | Lo que el revisor mire, o el sistema en ejecución |
| Cómo decide | Razona flujo de datos y contexto del repo | Patrones deterministas | Criterio y explotación real |
| Repetibilidad | Variable: es un modelo | Alta: misma regla, mismo resultado | Depende de la persona |
| Dependencias vulnerables | Excluidas por prompt | Según la herramienta | Solo si el alcance lo incluye |
| Coste observado | 0,79 USD en un diff de 17 líneas | Infraestructura propia | Horas de alguien senior |
| Límite o riesgo | Prompt injection en PRs externas, verdes falsos en CI | Ruido y reglas que no conocen tu dominio | Lento, no escala a cada PR |
Límites: qué no sustituye /security-review
No sustituye al SAST. Un modelo no garantiza el mismo resultado dos veces, y un gate de seguridad necesita reglas que fallen siempre igual. Úsalo como segunda opinión que entiende contexto, no como la regla que bloquea el merge.
No audita dependencias. El prompt excluye las librerías desactualizadas. Esa capa es otra, la que cuento en cómo auditar tus dependencias de npm y pip.
No es un pentest. La documentación aclara que la revisión lee el código de tu checkout, no un servicio desplegado. Infraestructura, cabeceras reales o un WAF mal configurado quedan fuera.
No mira el código que ya tenías. Para el repo entero, la doc remite al plugin Claude Security, un escaneo multiagente del repositorio completo.
Tampoco protege tu máquina del agente. Ese es otro problema, el de los guardrails de terminal y base de datos. Aquí hablamos del código que sale de esa máquina.
¿Merece la pena pasar /security-review en cada rama?
Sí. Ejecútalo antes de pedir el merge; si falla, crea origin/HEAD y repite. En un par de minutos sabes si el último cambio, tuyo o del agente, abrió una puerta.
Mi tesis: el agente escribe más código del que puedes leer con ojos de atacante, y este comando abarata esa lectura en cada rama.
En Construye con IA monto el flujo completo con Claude Code, de la idea al producto, con estas comprobaciones dentro del ciclo. Y si quieres que el agente trabaje contra contratos verificables desde el principio, eso hacemos en el workshop SDD + Agentic Engineering.
Preguntas frecuentes
¿/security-review revisa todo mi repositorio?
No. Revisa solo el diff entre tu rama y la rama por defecto de origin, e ignora los problemas que ya existían. Para escanear el repositorio completo, la documentación remite al plugin Claude Security.
¿Por qué falla con "ambiguous argument origin/HEAD"?
Tu clon no tiene origin/HEAD, algo habitual en CI. Créala con git remote set-head origin <rama-por-defecto> y vuelve a ejecutarlo.
¿Puedo usar Claude Code security review en pull requests de forks?
El README de la Action lo desaconseja porque no está endurecida contra prompt injection. Limítala a PRs de confianza y exige aprobación para contribuidores externos en la configuración de Actions.
¿Cómo reduzco los falsos positivos en mi proyecto?
En local, copia security-review.md a .claude/commands/ y edita la sección de filtrado. En la Action, usa false-positive-filtering-instructions con un fichero propio y comprueba que la ruta se respeta.
¿Sustituye a Semgrep o a Dependabot?
No. Semgrep aplica reglas deterministas a todo el código y el escaneo de dependencias cubre lo que este prompt excluye. Son capas distintas.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
¿Te resultó útil este artículo?
Compártelo con tu comunidad y ayuda a otros desarrolladores.
