123% más CVE notificadas al día en 2026 que el año pasado.

Dependencias

¿Qué es una dependencia transitiva?

Una dependencia transitiva es un paquete que su software utiliza porque otro paquete lo necesita. Usted nunca la declaró, pero está en lo que distribuye, con sus propias vulnerabilidades y su licencia. Así puede verlas, corregirlas y demostrar cuáles entraron en cada versión.

Actualizado el

A vulnerable transitive dependency and its fix path An app declares two direct dependencies, express and hbs. Express brings in body-parser and send, which bring in raw-body and mime-types. Hbs brings in handlebars, which is vulnerable. The path from the app through hbs to handlebars is highlighted: upgrade hbs, or override the handlebars version. your project direct transitive, depth 1 depth 2 my-app express hbs body-parser send handlebars vulnerable, required by hbs raw-body mime-types Fix path: upgrade hbs, or override the handlebars version

Dependencias directas y transitivas

Una dependencia directa es la que usted declara en su manifiesto. Una dependencia transitiva es la que declaran sus dependencias, y las de estas a su vez, hasta donde llegue el árbol. El gestor de paquetes resuelve todo el árbol al instalar y, normalmente, registra el resultado en un lockfile.

Tome una aplicación que declara un solo paquete, express. Al ejecutar npm ls --all se ve lo que trae consigo esa única línea:

my-app
└─┬ express            ← directa: usted la declaró
  ├─┬ body-parser      ← transitiva, profundidad 1
  │ └── raw-body       ← transitiva, profundidad 2
  ├── cookie           ← transitiva, profundidad 1
  └─┬ send             ← transitiva, profundidad 1
    └── mime-types     ← transitiva, profundidad 2

El árbol real es más largo. La mayoría de los paquetes de una aplicación típica llegan de esta forma, lo que significa que la mayor parte del código que usted distribuye la eligió el gestor de paquetes, no usted.

Dependencia directa Dependencia transitiva
Quién la eligió Su equipo, en el manifiesto El gestor de paquetes, a partir de los manifiestos de sus dependencias
Dónde aparece Manifiesto y lockfile Lockfile, si lo hay
Quién controla la versión Usted El rango de versiones del paquete padre, salvo que usted lo anule
Cómo se corrige una vulnerabilidad Actualizándola Actualizando el paquete padre o forzando la versión

Por qué importan las dependencias transitivas

Conllevan los mismos riesgos que las dependencias directas, con menos visibilidad y menos control.

  • Vulnerabilidades. Cuando se divulgó Log4Shell, una vulnerabilidad de día cero en log4j, el equipo de Open Source Insights de Google encontró 35.863 artefactos de Maven Central que dependían del código afectado de log4j. Unos 7.000 dependían de él directamente. La mayoría lo incorporaba como dependencia transitiva, y muchos no pudieron corregirse hasta que un paquete intermedio publicó primero una corrección.
  • Ataques a la cadena de suministro. La puerta trasera de xz utils (CVE-2024-3094) llegó a OpenSSH sin que OpenSSH dependiera de xz. Varias distribuciones de Linux parchean OpenSSH para que admita las notificaciones de systemd, y libsystemd depende de liblzma, la biblioteca que proporciona xz.
  • Licencias. Cada paquete transitivo tiene su propia licencia. Una licencia copyleft tres niveles más abajo obliga tanto como una que usted haya añadido.
  • Cambios incompatibles. Un paquete padre que acepta un rango de versiones deja entrar una nueva versión transitiva en la siguiente instalación desde cero, aunque nada haya cambiado en su manifiesto.

Cómo enumerar sus dependencias transitivas

Todos los gestores de paquetes principales pueden mostrar el árbol resuelto:

Ecosistema Comando
npmnpm ls --all
pnpmpnpm list --depth Infinity
Python (uv)uv tree
Python (pip)pipdeptree
Gogo mod graph
Rustcargo tree
Mavenmvn dependency:tree
Gradlegradle dependencies

Para averiguar por qué está ahí un paquete concreto, pida la ruta hasta él: npm explain <package>, pnpm why, yarn why o cargo tree -i <crate>. Para trabajar con las rutas en lugar de mostrarlas, consulte grafos de dependencias.

Cómo corregir una dependencia transitiva vulnerable

  1. Actualice el paquete padre. Busque la dependencia directa que incorpora el paquete y pase a una versión que exija una versión corregida. Es la corrección más limpia, porque los mantenedores del paquete padre la han probado.
  2. Actualice el lockfile. Si el rango de versiones del paquete padre ya permite la versión corregida, basta con actualizar la entrada del lockfile, por ejemplo con cargo update -p <crate> o ejecutando de nuevo npm update.
  3. Fuerce la versión. Si el paquete padre no ha publicado una corrección, fuerce usted la versión: overrides en npm y pnpm, resolutions en Yarn, un archivo de restricciones con pip o un requisito más alto en go.mod. Pruébelo, porque el paquete padre nunca se publicó con esa versión.
  4. Sustituya o elimine el paquete padre. Si nada de lo anterior funciona, puede que ya no merezca la pena conservar la dependencia que incorpora el paquete.

Algunas herramientas de análisis de composición de software añaden análisis de alcanzabilidad, que comprueba si su código puede llegar a invocar la función vulnerable, para decidir cuál de estas correcciones va primero. Consulte la comparativa de herramientas de SCA para ver las opciones.

Por qué el lockfile no lo cuenta todo

La mayoría de las herramientas construyen su visión de las dependencias transitivas a partir del lockfile. Eso funciona cuando el lockfile existe, está actualizado y es lo único a partir de lo que instala el build. En CI, a menudo no es así:

  • Sin lockfile. Un requirements.txt con rangos de versiones o un proyecto que nunca añadió su lockfile al repositorio se resuelve de nuevo en cada build, de modo que las versiones transitivas pueden cambiar entre builds.
  • Cachés. Las cachés de CI restauran paquetes de ejecuciones anteriores en lugar de descargarlos, y lo que contienen no siempre coincide con lo que dice el lockfile actual. Consulte lo que oculta la caché de GitHub Actions.
  • Herramientas de build. Los linters, los compiladores, los generadores de código y los pasos de configuración traen al build sus propios árboles de dependencias. No están en el manifiesto de su aplicación, pero se ejecutan con acceso a su código fuente y a sus secretos.
  • Scripts de instalación y descargas. El script de instalación de un paquete puede descargar más código, y un paso del build puede descargar un binario directamente. Ninguno deja una entrada en un lockfile.

El único registro completo de las dependencias transitivas que entraron en una versión es el que se toma mientras se compila esa versión. SBOM durante el build explica la diferencia entre registrar un build y escanear sus archivos después.

Las dependencias transitivas y el CRA

El Cyber Resilience Act de la UE exige a los fabricantes elaborar una SBOM que abarque «como mínimo, las dependencias de primer nivel de los productos» (anexo I, parte II, punto 1). Las dependencias transitivas no se mencionan, así que el mínimo legal es inferior a lo que sugieren muchas guías. Pero el CRA también le exige identificar y gestionar las vulnerabilidades de los componentes que contiene su producto, y un paquete transitivo vulnerable es uno de ellos. Una SBOM que se detiene en el primer nivel deja fuera de ese proceso la mayor parte de su árbol de dependencias. Consulte los requisitos de SBOM del CRA para ver los detalles.

Cómo sigue CRACI las dependencias transitivas

CRACI es un runner de GitHub Actions que registra el build en lugar de escanearlo. Mientras se ejecuta cada job, un proxy que entiende de paquetes registra cada paquete que descarga el job, a cualquier profundidad del árbol, incluidos los paquetes restaurados desde cachés de CI. Eso ofrece una visión más completa de las dependencias en uso que las herramientas basadas en escáneres.

  • Todas las profundidades, con honestidad. La SBOM de cada job lleva un estado de completitud, de modo que usted sabe cuándo un registro no pudo verlo todo.
  • El árbol, a la vista. Un grafo de dependencias muestra las capas de dependencias de la SBOM, en varias vistas.
  • Exportaciones que las incluyen. Las exportaciones en CycloneDX y SPDX incluyen las dependencias transitivas, cada una con su licencia declarada.
  • Qué builds se vieron afectados. Cuando aparece una nueva vulnerabilidad, el historial de builds muestra qué builds anteriores contenían el paquete vulnerable, directo o transitivo, de modo que usted conoce el periodo en que lo distribuyó (consulte ¿nos afecta una CVE?). El historial depende de su retención, 180 días por defecto.
  • Controles de política. Un build que contiene una CVE concreta se puede bloquear antes de que se distribuya.

CRACI no hace análisis de alcanzabilidad. Si necesita saber si su código invoca una función vulnerable, combínelo con una herramienta de SCA que lo haga. Consulte la generación de SBOM en CRACI o reserve una demo para registrar uno de sus propios builds.

Dependencias transitivas: preguntas frecuentes

¿Qué es una dependencia transitiva?

Una dependencia transitiva es un paquete que su software utiliza porque otro paquete lo necesita. Si su aplicación depende de la biblioteca A y A depende de la biblioteca B, entonces B es una dependencia transitiva, o indirecta, de su aplicación. Usted nunca la declaró, pero se distribuye con su software.

¿Cuál es la diferencia entre una dependencia directa y una transitiva?

Una dependencia directa es la que usted declara en su manifiesto, como package.json, pyproject.toml o go.mod. Una dependencia transitiva es la que declaran sus dependencias directas, a cualquier profundidad. Usted elige las dependencias directas; el gestor de paquetes elige las transitivas al resolver el árbol.

¿Una dependencia transitoria es lo mismo que una dependencia transitiva?

Sí, en la práctica. «Dependencia transitoria» es un lapsus habitual por «dependencia transitiva». El término correcto es transitiva, de la relación transitiva: si A depende de B y B depende de C, entonces A depende de C.

¿Cómo corrijo una vulnerabilidad en una dependencia transitiva?

Primero actualice la dependencia directa que la incorpora, si existe una versión que traiga la corrección. Si no, fuerce la versión corregida con el mecanismo de su gestor de paquetes, como npm overrides, Yarn resolutions o un archivo de restricciones de pip, y compruebe que el paquete padre sigue funcionando con ella.

¿Cómo enumero todas las dependencias transitivas?

Todos los gestores de paquetes pueden mostrar el árbol resuelto: npm ls --all, pnpm list --depth Infinity, uv tree o pipdeptree, go mod graph, cargo tree, mvn dependency:tree o gradle dependencies. Para saber qué instaló realmente un build de producción, registre el propio build.

¿El Cyber Resilience Act de la UE exige incluir las dependencias transitivas en la SBOM?

El reglamento fija el mínimo en «como mínimo, las dependencias de primer nivel de los productos» (anexo I, parte II, punto 1). Las dependencias transitivas no se mencionan, pero un paquete transitivo vulnerable sigue estando en su producto, y el CRA le exige gestionar las vulnerabilidades de los componentes que distribuye.

Vea todas las dependencias que incorporó su build

Ejecute un workflow de GitHub Actions en CRACI y obtenga una SBOM registrada de cada paquete que descargó, a cualquier profundidad del árbol.

Reservar una demo