Escaneo SAST
Las auditorías de dependencias cubren el código que importaste; SAST cubre el código que escribiste. Hace coincidencia de patrones (y, con modo de flujo de datos, rastrea el flujo de datos) para las fallas clásicas: inyección de comandos/SQL, path traversal, deserialización insegura, eval/ejecución dinámica sobre entradas no confiables, criptografía hardcodeada, falta de controles de autenticación. Una alta tasa de falsos positivos es inherente: la disciplina es triaje por alcanzabilidad, no ignorar en bloque.
Cuándo ejecutarlo
- Antes de un lanzamiento, sobre el diff o todo el árbol.
- Cuando agregas código que maneja entradas no confiables (una nueva herramienta, un endpoint, un parser, una salida al shell).
- En CI sobre PRs (con ámbito de diff, para que sea rápido y solo marque problemas nuevos).
Ejecutarlo
# semgrep — los conjuntos de reglas de seguridad. `auto` selecciona reglas según los lenguajes detectados.
semgrep scan --config auto --error .
# Conjuntos de reglas enfocados y de mayor señal (menos ruido que auto):
semgrep scan --config p/security-audit --config p/secrets --config p/command-injection .
# Solo diff (CI en un PR — rápido, solo HALLAZGOS NUEVOS):
semgrep scan --config auto --baseline-commit origin/main .
Para un análisis de flujo de datos más profundo (¿la entrada no confiable REALMENTE ALCANZA el sumidero?), CodeQL es más potente pero más pesado:
codeql database create db --language=javascript # o rust, python, …
codeql database analyze db --format=sarif-latest --output=results.sarif \
codeql/javascript-queries:codeql-suites/javascript-security-extended.qls
Triaje — rastrea, no descartes
Para cada hallazgo, rastrea la ruta fuente → sumidero:
- ¿La entrada está controlada por el atacante? Un
child_process.execsobre una constante hardcodeada está bien; sobre un parámetro de solicitud es un error de inyección de comandos. semgrep marca el sumidero; TÚ confirmas la fuente. - ¿Hay un sanitizador entre ellos? Si el valor es validado/escapado (un esquema zod, una lista blanca, una consulta parametrizada) antes del sumidero, es un falso positivo: márcalo con
# nosemgrep: <id-regla>con una línea de explicación, no un ignore desnudo. - ¿Real? Arregla en la fuente (valida/escapa la entrada) o en el sumidero (parametriza, usa la API segura), no suprimiendo la advertencia.
Nunca deshabilites una regla en bloque para limpiar el tablero — suprimirás el único acierto real entre el ruido. Suprime por línea, con una razón.
Qué arreglar realmente (mayor valor primero)
- Inyección (comandos/SQL/plantillas) en cualquier ruta accesible al usuario — la clase de mayor severidad y más explotada.
- Path traversal — rutas no validadas que alcanzan lecturas/escrituras de archivos (un agente que escribe archivos es exactamente este riesgo; pon una compuerta con una verificación de alcance).
- Exec/eval inseguros de cadenas dinámicas.
- Criptografía hardcodeada / aleatoriedad débil en un contexto de seguridad.
El límite
SAST ve el código fuente de un repositorio estáticamente — no puede ver la configuración en tiempo de ejecución, una ruta de código impulsada por variables de entorno, o una falla que solo surge a través de un límite de servicio. Complementa, nunca reemplaza, un modelo de amenazas real y [[dependency-audit]]. Para un entorno de agente/herramienta, el control más fuerte es a menudo arquitectónico (un núcleo que controla cada acción) en lugar de por línea — SAST valida el código ALREDEDOR de ese límite. Incorpóralo en [[security-preflight]].