Cómo gestionar vulnerabilidades en dependencias

Seguridad Y Cumplimiento

18 abr 2026

Controla y reduce riesgos en la cadena de suministro: escaneo continuo, archivos lock, CI/CD y registros privados.

Miles de paquetes maliciosos y brechas de seguridad han puesto en evidencia los riesgos que conllevan las dependencias de software. Cada librería que instalas, ya sea directa o transitiva, puede convertirse en un punto de ataque. Desde técnicas como el typosquatting hasta ataques de dependency confusion, las amenazas son reales y frecuentes.

Para proteger tus proyectos, necesitas un enfoque claro y herramientas específicas. Aquí tienes los pasos clave:

  • Escaneo constante: Usa herramientas como Dependabot para detectar vulnerabilidades en dependencias directas y transitivas.

  • Archivos lock: Garantizan versiones consistentes y protegen contra manipulaciones.

  • Automatización en CI/CD: Integra escaneos y bloqueos de vulnerabilidades en tus pipelines.

  • Actualización y limpieza: Elimina dependencias no utilizadas y actualiza a versiones seguras.

  • Sobrescrituras y parches: Corrige vulnerabilidades en dependencias anidadas cuando no haya actualizaciones disponibles.

  • Registros privados: Refuerzan la seguridad al controlar el acceso y evaluar paquetes antes de usarlos.

Proteger tu código no es solo una tarea técnica, es una responsabilidad. Con buenas prácticas y herramientas adecuadas, puedes reducir los riesgos y mantener un entorno seguro.

6 pasos clave para gestionar vulnerabilidades en dependencias de software

6 pasos clave para gestionar vulnerabilidades en dependencias de software

10. Buscar vulnerabilidades en las dependencias de tus proyectos

Cómo encontrar vulnerabilidades en dependencias

Detectar problemas de seguridad en tus dependencias implica entender cómo funciona la resolución de dependencias. Cuando instalas un paquete directo (el que defines explícitamente en tu package.json o archivo equivalente), este puede incluir una cadena de dependencias transitivas que se extiende a varios niveles de profundidad. Conocer este árbol completo es clave para identificar riesgos, incluso en componentes que tu código no utiliza directamente.

Herramientas como Dependabot Alerts y Dependency Review son excelentes aliadas para este propósito. Estas soluciones analizan automáticamente tanto dependencias directas como transitivas, utilizando la GitHub Advisory Database. Esta base de datos contiene avisos de seguridad desde 2017 y abarca ecosistemas como npm, Maven, NuGet, pip y RubyGems. Por ejemplo, Dependency Review puede detectar dependencias inseguras mientras revisas pull requests, lo que ayuda a evitar que vulnerabilidades lleguen a producción. Integrar estas herramientas en tu pipeline de CI/CD asegura un monitoreo constante cada vez que actualizas dependencias.

Riesgos de seguridad derivados de dependencias vulnerables

Identificar vulnerabilidades es solo el primer paso. Cada dependencia insegura puede suponer un riesgo serio para tu sistema. Según la OWASP Foundation, los "Componentes Vulnerables y Obsoletos" figuran regularmente entre los diez mayores riesgos de seguridad para aplicaciones web. Los peligros más comunes incluyen filtraciones de datos, ataques a la cadena de suministro y fallos del sistema, todos ellos capaces de comprometer tu infraestructura.

Un solo componente vulnerable puede abrir la puerta a múltiples ataques. Además, actualizar una dependencia directa puede provocar cambios en toda la cadena de dependencias, lo que podría introducir nuevas vulnerabilidades. Por eso, entender el proceso de resolución de dependencias es crucial. Sin este conocimiento, podrías ser víctima de ataques como el dependency confusion, donde los instaladores descargan paquetes públicos maliciosos en lugar de los internos previstos.

Cómo los archivos lock controlan las versiones de dependencias

Los archivos lock, como package-lock.json, yarn.lock o Pipfile.lock, son esenciales para gestionar las versiones de dependencias. Estos archivos actúan como un registro detallado que especifica exactamente qué versiones deben instalarse, incluidas las transitivas. Esto proporciona una visión completa de los componentes que tu código utiliza, incluso indirectamente.

Por ejemplo, en Node.js, si declaras el paquete glob (versión 8.0.2) en tu package.json, el archivo package-lock.json detallará toda la cadena de dependencias: glob 8.0.2 depende de minimatch 5.0.1, que a su vez depende de brace-expression 2.0.1, y este de balanced-match 1.0.2. Esto asegura que las mismas versiones se instalen en todos los entornos.

Además, los archivos lock incluyen hashes o firmas que verifican la integridad de cada paquete, protegiéndote contra manipulaciones o ataques de confusión de dependencias. Las herramientas de seguridad automatizadas aprovechan estos archivos para identificar las versiones exactas en uso y alertarte sobre vulnerabilidades recién descubiertas en esas versiones específicas.

Escaneo y auditoría de tus dependencias

Una vez identificados los riesgos en tus dependencias, es clave mantener un proceso continuo de escaneo y auditoría. Esto implica implementar herramientas capaces de detectar vulnerabilidades de manera automática. Hoy en día, estas herramientas no solo revisan las dependencias directas, sino también las transitivas, ofreciendo un panorama completo de los posibles riesgos. Además, se integran fácilmente con los procesos de actualización y mantenimiento posteriores.

Herramientas de escaneo automatizado

Dependabot Alerts analiza la rama principal de tu repositorio y te avisa cuando se detecta una nueva vulnerabilidad en la GitHub Advisory Database o si cambia el grafo de dependencias de tu proyecto. Cada vulnerabilidad genera una alerta única, lo que minimiza el ruido y facilita la gestión.

Dependabot Security Updates va más allá al generar automáticamente pull requests para actualizar dependencias vulnerables a versiones que ya incluyen un parche de seguridad. Estas actualizaciones incluyen un porcentaje de compatibilidad, calculado a partir de pruebas de CI en otros repositorios públicos, lo que te da una idea de la probabilidad de que la actualización no afecte negativamente a tu proyecto. Por ejemplo, un 95% de compatibilidad indica que la actualización ha tenido éxito en la mayoría de los proyectos similares.

Para usar estas herramientas, es necesario activar el grafo de dependencias en la configuración del repositorio, ya que es un requisito previo para las alertas y actualizaciones de seguridad. También puedes aplicar filtros como scope:development para diferenciar entre dependencias de desarrollo y de producción. De esta manera, puedes priorizar las correcciones en producción, ya que las vulnerabilidades en este entorno representan un mayor riesgo para tu aplicación en vivo.

Añadir escaneos a pipelines de CI/CD

Una vez configuradas las herramientas automatizadas, el siguiente paso es integrarlas en tu pipeline de CI/CD. Esto asegura que cada cambio sea evaluado antes de entrar en producción. La Dependency Review Action es ideal para este propósito, ya que identifica dependencias inseguras en los pull requests antes de que se fusionen con la rama principal. Además, puedes configurarla para que bloquee automáticamente un pull request si introduce una dependencia con un nivel de gravedad "alto" o "crítico".

Esta integración se mantiene activa gracias al grafo de dependencias, que analiza automáticamente los archivos manifest (como package-lock.json o yarn.lock) cada vez que hay cambios en la rama principal. Para entornos de compilación más complejos, puedes usar la Dependency Submission API, que permite enviar las dependencias resueltas durante el proceso de compilación al grafo de dependencias para un análisis detallado.

También puedes vincular estos escaneos con las reglas de protección de ramas para evitar que se fusionen pull requests que contengan vulnerabilidades críticas. Si trabajas con paquetes internos o privados, asegúrate de configurar Dependabot con los tokens de acceso necesarios para que estas dependencias también sean escaneadas durante el proceso de CI.

"La detección y la corrección tempranas reducen el riesgo de una respuesta a incidentes costosa, revisiones de emergencia y daños de reputación." – GitHub Docs

Estas herramientas de escaneo automatizado son compatibles con los principales ecosistemas, como npm, Maven, NuGet, pip, RubyGems y Composer. Además, la GitHub Advisory Database, que respalda estas herramientas, incluye avisos de seguridad desde 2017, lo que garantiza una cobertura histórica amplia para identificar vulnerabilidades incluso en dependencias más antiguas.

Actualización y mantenimiento de dependencias

Después de identificar las vulnerabilidades, es clave mantener un entorno limpio y actualizado para minimizar riesgos. Mantener tus dependencias al día no solo mejora la seguridad, sino que también optimiza el rendimiento del proyecto. Un sistema con paquetes innecesarios no solo se vuelve más lento, sino que también aumenta la superficie de ataque.

Eliminar dependencias sin uso

El primer paso es identificar qué paquetes son realmente necesarios. Herramientas como depcheck pueden analizar tu proyecto y detectar dependencias declaradas en package.json que no se usan en el código. Ejecutar npx depcheck de forma regular ayuda a localizar estas "dependencias fantasma" y eliminarlas con seguridad.

Si buscas un análisis más completo, npm-check ofrece un informe interactivo que no solo identifica paquetes sin uso, sino que también señala cuáles están desactualizados. Esta herramienta es más visual y proporciona recomendaciones de actualización, además de detectar dependencias innecesarias. Incorporar estas revisiones en tu pipeline de CI/CD asegura que los archivos de requisitos estén optimizados antes de cada despliegue.

"Si sigues instalando dependencias que no se usan en tu aplicación, aumentará el tamaño de las dependencias y el riesgo de que se vea afectada por una vulnerabilidad en esas dependencias." – Google Cloud

Actualizar a versiones seguras

El versionado semántico (SemVer) organiza las versiones en el formato MAJOR.MINOR.PATCH, donde los cambios MAJOR pueden romper compatibilidad, los MINOR añaden funciones sin riesgo, y los PATCH corrigen errores. Los prefijos como ^ (permite actualizaciones menores y parches) o ~ (solo parches) ayudan a equilibrar seguridad y estabilidad.

Símbolo

Ejemplo

Rango permitido

Nivel de riesgo

^

^1.2.3

>=1.2.3 <2.0.0

Medio (nuevas funciones seguras)

~

~1.2.3

>=1.2.3 <1.3.0

Bajo (solo correcciones)

=

1.2.3

1.2.3

Muy bajo (sin cambios automáticos)

Herramientas como npm-check-updates te permiten explorar versiones más recientes, incluso fuera de las restricciones de SemVer. Sin embargo, es importante actualizar cada dependencia de forma individual y probar cada cambio para evitar problemas en producción. Los archivos de bloqueo, como package-lock.json o yarn.lock, aseguran que las mismas versiones exactas se instalen en todos los entornos, garantizando consistencia y reproducibilidad.

Una vez completadas las actualizaciones, verifica siempre que los paquetes provengan de fuentes confiables.

Elegir fuentes de paquetes confiables

Optar por registros privados en lugar de descargar directamente desde repositorios públicos como npm o PyPI ofrece varias ventajas. Estos registros permiten centralizar artefactos, controlar el acceso mediante IAM y analizar vulnerabilidades antes de que los paquetes lleguen a tu proyecto. Funcionan como un "proxy de paso", cacheando y evaluando los paquetes públicos antes de integrarlos, lo que refuerza la seguridad.

Para evaluar la calidad de los paquetes, herramientas como Scorecards asignan una puntuación de seguridad de 0 a 10 basada en factores como prácticas de la cadena de suministro. También es útil verificar la frecuencia de actualizaciones, el historial de vulnerabilidades en bases de datos como GitHub Advisory Database y la compatibilidad de licencias. Para evitar ataques de confusión de dependencias, configura repositorios virtuales con prioridades que aseguren que los paquetes internos prevalezcan sobre los públicos con el mismo nombre.

Solucionar vulnerabilidades en dependencias anidadas

Las vulnerabilidades más graves suelen encontrarse en las dependencias transitivas, es decir, aquellas que se instalan automáticamente a través de tus paquetes directos. Si una de estas dependencias anidadas tiene un fallo de seguridad y no ha sido actualizada por la dependencia directa, tendrás que intervenir manualmente.

Usar sobrescrituras de dependencias

Cuando detectes vulnerabilidades, el siguiente paso es intervenir en las dependencias anidadas afectadas. Los gestores de paquetes modernos permiten forzar versiones específicas utilizando campos nativos en el archivo package.json. Por ejemplo:

  • npm (a partir de la versión 8.3.0) utiliza el campo overrides.

  • Yarn (v1) emplea resolutions.

  • pnpm ofrece tanto overrides como hooks de paquetes.

Puedes aplicar sobrescrituras de forma global o específica según lo necesites. Por ejemplo, en lugar de definir "webpack": "5.74.0" de manera global, podrías configurarlo específicamente para una dependencia directa como "react-scripts": { "webpack": "5.74.0" }. Esto reduce los efectos secundarios al limitar el cambio al contexto necesario. Además, npm permite usar el símbolo "." para sobrescribir la versión del propio paquete mientras ajustas sus dependencias internas.

"Los overrides te permiten ser el jefe de tu árbol de dependencias, incluso de las partes que no escribiste." – Shubham Verma

Después de implementar una sobrescritura, realiza una instalación limpia y verifica el archivo de bloqueo (package-lock.json o yarn.lock) para asegurarte de que la versión vulnerable ha sido reemplazada correctamente. También puedes incluir patch-package en el script postinstall para aplicar parches automáticamente tras cada instalación.

Bifurcar dependencias cuando sea necesario

Si las sobrescrituras no son una opción viable, considera bifurcar la dependencia como una medida temporal. Esto puede ser necesario si el repositorio está abandonado o si necesitas un parche urgente y los mantenedores tardan en aprobar una solución. Sin embargo, mantener un fork completo puede ser complicado, especialmente si la dependencia afectada está anidada en varios niveles del árbol.

Como alternativa más sencilla, Yarn 2+ y pnpm ofrecen herramientas nativas de parcheo, como yarn patch y pnpm patch. Estas herramientas extraen el código a una carpeta temporal para que puedas editarlo. Después, generan un archivo .patch que se integra en tu repositorio. Por ejemplo, al usar yarn patch, el package.json cambia al protocolo patch: y apunta al archivo .patch local, el cual debe añadirse al sistema de control de versiones para que todo el equipo pueda beneficiarse del arreglo.

Estas soluciones deben considerarse temporales. Revisa regularmente si la dependencia directa ha actualizado sus requisitos para eliminar la sobrescritura o el parche. Si el parche es demasiado complicado (por ejemplo, debido a código minificado u ofuscado), clona el repositorio original, realiza los cambios necesarios en la carpeta src y recompílalo. Esto asegura que el paquete sea funcional y seguro mientras esperas una solución oficial.

Configurar políticas de seguridad y automatización

Reaccionar ante vulnerabilidades no es suficiente; necesitas establecer reglas claras que impidan que código inseguro llegue a producción. Una de las medidas clave es el anclaje obligatorio de versiones mediante archivos de bloqueo como package-lock.json, yarn.lock o Pipfile.lock. Esto asegura compilaciones reproducibles y evita que versiones no verificadas se introduzcan accidentalmente. Además, define criterios de bloqueo que eviten la fusión de pull requests si introducen vulnerabilidades nuevas o no actualizan paquetes críticos. Estas acciones complementan las prácticas de escaneo y actualización mencionadas anteriormente.

Crear políticas de seguridad

Una política de seguridad sólida debe priorizar el uso de registros privados sobre públicos para protegerse contra ataques de "dependency confusion". Este tipo de ataque ocurre cuando paquetes maliciosos con nombres similares a los internos logran infiltrarse en un proyecto. También es importante exigir firmas digitales y hashes para evitar manipulaciones. Mantén un Software Bill of Materials (SBOM) actualizado, que registre todas las dependencias directas y transitivas en tu organización. Este inventario, exportable en formatos como SPDX o CycloneDX, proporciona una visión clara de las dependencias, facilitando su gestión.

Elemento de política

Propósito

Método de implementación

Anclaje de versiones

Control estricto para reforzar la seguridad

Uso obligatorio de archivos de bloqueo en todos los entornos

Bloqueo de fusiones

Evitar que riesgos lleguen a producción

Compuertas CI/CD que fallan ante CVE de alta gravedad

Control de fuentes

Verificación en toda la cadena de suministro

Registros privados con validación de integridad

Plan de triaje

Estandarizar la gestión de alertas

Asignación de roles para revisar, justificar o parchear alertas

Con estas políticas en marcha, automatizar las actualizaciones de seguridad es el siguiente paso lógico.

Automatizar actualizaciones de seguridad

Herramientas como Dependabot pueden generar pull requests automáticos cuando se detectan actualizaciones de seguridad críticas, reduciendo el tiempo de exposición a vulnerabilidades. Para optimizar el flujo de trabajo, agrupa las actualizaciones críticas y prioriza los riesgos que afectan directamente a producción. Además, programa auditorías automatizadas periódicas para identificar dependencias obsoletas o sin mantenimiento, más allá del escaneo en tiempo real. Implementa reglas de triaje automático que filtren alertas de bajo impacto, como vulnerabilidades en dependencias usadas solo en entornos de desarrollo, permitiendo que el equipo se centre en lo que realmente importa.

Seguimiento de avisos de seguridad

Una vez que las políticas están definidas, mantener una vigilancia constante es fundamental. Suscríbete a boletines de seguridad específicos para los lenguajes y frameworks que utiliza tu proyecto. Integra bases de datos como la GitHub Advisory Database o la Open Source Vulnerability (OSV) database directamente en tu flujo de trabajo. Esto permite detectar amenazas conocidas de manera automatizada. Además, utiliza acciones de revisión de dependencias que analicen los pull requests en busca de vulnerabilidades antes de fusionarlos con la rama principal. Para mayor seguridad, evita extraer directamente de fuentes públicas. En su lugar, emplea un registro privado que almacene en caché y escanee las dependencias externas antes de que lleguen a tu entorno local, asegurando una respuesta ágil ante nuevas amenazas.

Conclusión

Mantener bajo control las vulnerabilidades en dependencias de terceros exige una vigilancia constante en todas las fases del desarrollo. Las auditorías regulares ayudan a descubrir riesgos ocultos en dependencias transitivas, mientras que las actualizaciones puntuales eliminan brechas de seguridad conocidas antes de que puedan ser explotadas. Automatizar políticas de seguridad, como bloquear fusiones en caso de vulnerabilidades críticas, asegura que ningún código inseguro llegue a producción.

Para entender la magnitud del problema, desde 2019 se han detectado más de 700.000 paquetes maliciosos. Además, en 2024, el 22 % de las brechas de seguridad se originaron por credenciales expuestas. Cada librería, imagen Docker o script en tu pipeline representa un posible punto de entrada para ataques.

Adoptar estrategias como el escaneo automatizado, el anclaje de versiones mediante archivos de bloqueo y el uso de registros privados puede reducir drásticamente la superficie de ataque. Incorporar compuertas en los pipelines de CI/CD que detengan el proceso ante vulnerabilidades críticas (CVE de alta gravedad) convierte la seguridad en un requisito técnico imprescindible. Aplicar estas medidas garantiza que cada actualización refuerce tu sistema.

Estas acciones no solo protegen los proyectos actuales, sino que también establecen bases sólidas para un desarrollo seguro a futuro. En un entorno donde el 23,8 % de los ataques a la cadena de suministro se aprovechan de vulnerabilidades en pipelines de compilación, actuar de forma preventiva no es solo una opción, es una necesidad para mantener la seguridad a largo plazo.

FAQs

¿Qué hago si la vulnerabilidad está en una dependencia transitiva?

Si la vulnerabilidad se encuentra en una dependencia transitiva, lo mejor es actualizar esa dependencia para corregir el problema. Para hacerlo sin causar problemas en otras partes del proyecto, utiliza herramientas que gestionen dependencias transitivas de manera eficiente. También es fundamental revisar las vulnerabilidades detectadas con plataformas especializadas en análisis de seguridad.

Además, establece auditorías regulares en tus procesos y automatiza las revisiones de seguridad. Esto te permitirá identificar y actualizar de forma rápida las dependencias vulnerables, incluidas aquellas transitivas, evitando posibles riesgos en el futuro.

¿Cuándo debo bloquear un PR por una alerta de dependencia?

Debes bloquear un Pull Request (PR) si la alerta de dependencia señala una vulnerabilidad crítica que no puede solucionarse de inmediato y que supone un riesgo importante para la seguridad del proyecto. En estos casos, es fundamental priorizar una solución rápida para reducir la exposición y garantizar la protección del desarrollo.

¿Cómo evito ataques de “dependency confusion” con paquetes internos?

Para evitar ataques de "dependency confusion", es importante tomar medidas específicas que refuercen la seguridad en la gestión de dependencias. Aquí te dejamos algunos pasos clave:

  • Configura los registros de paquetes: Asegúrate de que las dependencias internas tengan prioridad sobre los paquetes públicos. Esto evita que un paquete externo con un nombre similar reemplace a tus dependencias internas.

  • Verifica la autenticidad de los paquetes: Implementa procesos que certifiquen que los paquetes utilizados provienen de fuentes confiables.

  • Gestión estricta de versiones: Controla cuidadosamente las versiones de tus dependencias para evitar actualizaciones inesperadas o maliciosas.

  • Restringe el acceso a registros privados: Limita quién puede acceder y publicar en tus registros internos para reducir riesgos.

  • Usa controles automatizados: Implementa herramientas de monitorización y auditoría que detecten rápidamente cualquier intento sospechoso de ataque.

Estas prácticas pueden ayudarte a proteger tus proyectos frente a este tipo de amenazas. La prevención siempre será tu mejor defensa.

Publicaciones de blog relacionadas