SAST vs SCA se resume en una pregunta: ¿de quién es el código que estás revisando? El SAST (static application security testing) analiza el código que escribe tu equipo. El SCA (software composition analysis) analiza el código open source que importás. Los dos son estáticos, los dos corren temprano en el pipeline y los dos aparecen en los mismos dashboards, por eso se confunden. Pero encuentran clases de problemas completamente distintas, y ninguno puede hacer el trabajo del otro.

En esta guía comparamos SAST y SCA en la práctica: qué encuentra cada uno, dónde se superponen, por qué la alcanzabilidad y los lockfiles definen cuán útil es el SCA, qué es el riesgo de licencias y cómo correr los dos sin tapar a tu equipo de alertas.

Qué hace el SAST

El SAST lee tu código fuente y arma un modelo de cómo se mueven los datos. Sigue el input no confiable (parámetros, headers, payloads de mensajes) hasta operaciones peligrosas (queries SQL, comandos de shell, render de templates, rutas de archivos) y reporta el camino vulnerable con archivo y línea. El SAST moderno basado en IA además razona sobre lógica que las reglas no pueden expresar, como un handler que se olvida de verificar de quién es un registro. En nuestra guía de herramientas SAST explicamos en qué se diferencian el enfoque por reglas y el AI SAST.

Hallazgos típicos de SAST: inyección SQL, command injection, sinks de XSS, path traversal, deserialización insegura, SSRF, credenciales hardcodeadas, criptografía débil y control de acceso roto en tus propios handlers.

Qué hace el SCA

El SCA arma un inventario de tus dependencias a partir de manifiestos y lockfiles (package-lock.json, Gemfile.lock, poetry.lock, go.sum, etc.), incluyendo las dependencias transitivas que nunca elegiste de forma directa. Después cruza cada paquete y versión contra bases de vulnerabilidades como OSV, la GitHub Advisory Database y la NVD, y te dice qué versión corrige el problema. Muchas herramientas también reportan licencias. Ese mismo inventario se puede exportar como un SBOM.

Hallazgos típicos de SCA: un CVE conocido en una versión de librería que estás entregando, un paquete abandonado, una dependencia con una licencia que choca con cómo distribuís tu producto.

Tabla comparativa: SAST vs SCA

DimensiónSASTSCA
Qué analizaEl código que escribió tu equipoLos paquetes de terceros de los que dependés
InputArchivos fuenteManifiestos y lockfiles
Qué encuentraVulnerabilidades nuevas y desconocidas en tu lógicaVulnerabilidades conocidas y publicadas (CVEs) y problemas de licencia
Fuente de conocimientoReglas, modelos de flujo de datos o razonamiento con IA sobre tu códigoBases de vulnerabilidades (OSV, GitHub Advisories, NVD)
Fix típicoCambiar tu códigoSubir a una versión corregida o reemplazar el paquete
UbicaciónArchivo y líneaPaquete, versión y camino de dependencias
Principal fuente de ruidoHallazgos que en realidad no son explotablesCVEs en código que nunca llamás
Cuándo aparecen hallazgos nuevosCuando cambia el códigoCuando cambia el código, y también cuando se publica un CVE nuevo para un paquete que ya usás

Esa última fila pesa más de lo que parece. Los resultados del SAST solo cambian cuando cambia tu código. Los del SCA pueden cambiar de un día para el otro sin ningún commit, porque alguien publicó un advisory de una librería que usás hace dos años. El SCA tiene que correr de forma continua, no solo en los pull requests.

Qué se le escapa a cada uno

Un bug que el SCA nunca va a ver

// invoices.js: tu código, sin ninguna dependencia vulnerable
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
  const invoice = await Invoice.findById(req.params.id);
  res.json(invoice); // falta: invoice.ownerId === req.user.id
});

Todos los paquetes pueden estar al día. La vulnerabilidad (un IDOR, parte del control de acceso roto) vive en tu lógica. Solo el análisis de tu propio código, sea SAST, code review o testing, la puede encontrar.

Un bug que el SAST normalmente no marca

// package.json
"dependencies": {
  "lodash": "4.17.20"
}

Las versiones de lodash anteriores a la 4.17.21 están afectadas por el CVE-2021-23337, una command injection a través de la función template, con severidad alta. Tu código puede verse perfectamente normal; el problema es la versión que fijaste. Las herramientas SAST en general no cruzan el interior de node_modules contra advisories. El SCA matchea [email protected] con el advisory y te dice que subas a la 4.17.21.

Dónde se superponen SAST y SCA

El límite no es tan prolijo, y de las zonas grises salen los incidentes:

  • Uso inseguro de una librería segura. PyYAML no es vulnerable, pero yaml.load(data, Loader=yaml.Loader) sobre input del usuario sí. El SCA ve un paquete sano; el SAST ve la llamada peligrosa. Así nacen muchas vulnerabilidades de ejecución remota de código.
  • Código vendorizado o copiado. Una librería copiada en vendor/ o pegada desde un snippet no aparece en ningún lockfile, así que el SCA la puede perder. El SAST la escanea como si fuera tuya, que es lo que ahora es.
  • Alcanzabilidad. Decidir si un CVE importa requiere los dos: el SCA dice qué función es vulnerable y el análisis de código dice si la llamás.
  • Configuración y supply chain. Workflows de CI, Dockerfiles, imágenes base y Terraform no son ni "lógica de tu app" ni "un paquete", pero son parte de lo que entregás. Un buen programa los cubre también, junto con un secret scanner para keys en el historial de git.

Reachability: la diferencia entre 400 alertas y 12

Una app JavaScript típica trae cientos de paquetes transitivos, y el SCA sobre ellos suele devolver una lista larga. Muchos de esos CVEs están en funciones que tu código nunca llama, o en tooling de desarrollo que nunca corre en producción. Tratarlos a todos como urgentes es la forma más rápida de que el equipo aprenda a ignorar el SCA.

El análisis de alcanzabilidad pregunta: ¿hay algún camino desde tu código hasta la función vulnerable? Si el advisory de lodash es sobre _.template y vos solo usás _.get, el hallazgo es real pero de baja prioridad. Si tu handler le pasa input del usuario a _.template, va primero en la lista. No todas las herramientas hacen reachability y ninguna es perfecta (los imports dinámicos y la reflexión dejan el call graph incompleto), pero incluso una versión aproximada, sumada a "¿es una dependencia de producción?", baja muchísimo el ruido.

Lockfiles: el SCA es tan bueno como su input

Si tu repo solo tiene "express": "^4.18.0" en un manifiesto, la herramienta de SCA tiene que adivinar qué versión corrés de verdad. Los lockfiles eliminan la adivinanza porque registran la versión exacta resuelta de cada dependencia directa y transitiva.

  • Commiteá tus lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml, Gemfile.lock, poetry.lock, Cargo.lock, go.sum).
  • Instalá desde ellos en CI (npm ci, bundle install --frozen y equivalentes) para que lo que escaneás sea lo que buildeás.
  • Ojo con los múltiples lockfiles en monorepos: cada servicio puede resolver versiones distintas.

Riesgo de licencias

La seguridad no es lo único que puede encontrar el SCA. Cada dependencia viene con una licencia, y algunas imponen obligaciones. Las permisivas como MIT, BSD o Apache 2.0 piden básicamente atribución. Las copyleft como GPL o AGPL pueden exigirte publicar código fuente bajo ciertas condiciones, y la AGPL extiende eso al software que ofrecés por red. Si una obligación aplica o no depende de cómo usás y distribuís el código, así que tomá los hallazgos de licencias como insumo para una revisión legal, no como un veredicto. Lo que importa desde ingeniería es tener el inventario para poder responder la pregunta.

Por qué necesitás los dos

Pensá tu aplicación como dos mitades. El SAST cubre la mitad que escribiste vos, donde nacen los bugs nuevos y desconocidos. El SCA cubre la mitad que importaste, donde se acumulan con el tiempo los bugs conocidos y publicados. Sin SAST, tu lógica de negocio queda sin revisar. Sin SCA, quedás ciego ante el próximo Log4Shell. Un setup práctico:

  1. En cada pull request: SAST sobre el código modificado y SCA sobre los manifiestos y lockfiles modificados, con hallazgos ordenados por explotabilidad.
  2. De forma continua: volver a cruzar las dependencias existentes contra advisories nuevos, porque los CVEs aparecen sin commits.
  3. Con una frecuencia fija: un escaneo completo del repo, incluyendo secretos en el historial y configuración de infraestructura.
  4. Periódicamente: testing dinámico y pentests para lo que el análisis estático no ve. Nuestra guía SAST vs DAST cubre esa capa.

Este es el núcleo práctico de DevSecOps: chequeos baratos y precisos temprano, chequeos caros donde solo ellos pueden ayudar.

Cómo hace Nurbak los dos

Nurbak corre SAST y SCA en el mismo escaneo. Conectás GitHub y elegís un repositorio. Su propio modelo de IA self-hosted analiza tu código (el análisis no manda tu código a OpenAI ni a Anthropic) y reporta vulnerabilidades explotables con archivo y línea. En la misma pasada revisa tus dependencias contra CVEs conocidos vía OSV y te dice a qué versión corregida subir, y marca configuraciones inseguras de GitHub Actions, Docker, Terraform y Kubernetes y secretos en el historial de git. Los resultados llegan como un score de 0 a 100 con explicaciones en lenguaje simple, y para un hallazgo que decidas arreglar puede abrir un Pull Request con el fix más un test de regresión de seguridad (el fix usa Claude, con tu consentimiento explícito). El escaneo gratis muestra completos los 3 hallazgos más importantes; los planes arrancan en USD 79/mes. Empezá por la página de software composition analysis.

Cómo elegir herramientas

  • Cobertura de tu stack: lenguajes para el SAST, ecosistemas de paquetes y formatos de lockfile para el SCA.
  • Versiones corregidas, no solo IDs de CVE: un hallazgo de SCA sin camino de upgrade es tarea para el hogar, no ayuda.
  • Priorización: explotabilidad, alcanzabilidad, dependencia de producción vs de desarrollo.
  • Flujo del developer: resultados en los pull requests, explicaciones claras, fixes sugeridos.
  • Manejo de datos: dónde se procesa tu código, sobre todo con análisis basado en IA.

Conclusión

SAST vs SCA no es una elección. El SAST encuentra los bugs que escribís; el SCA encuentra los bugs que importás. Se superponen en los bordes (cómo llamás a las librerías, reachability, código vendorizado), y justamente por esa superposición correrlos juntos rinde más que cualquiera por separado. Si ya tenés uno, sumá el otro. Un buen primer paso es revisar tu repo con software composition analysis y ver cuántos CVEs conocidos tenés hoy en el lockfile.

Lecturas relacionadas