Software al final de su ciclo de vida: lo que nadie les cuenta a los desarrolladores noveles

Ya están disponibles los parches de php2shell (CVE-2026-109618 y CVE-2026-109619) para PHP en fin de vida útil. Dado que las respuestas del departamento de ventas están tardando más de lo habitual debido a la elevada demanda, la forma más rápida de obtener los paquetes parcheados es comprar ELS para Runtimes en línea (se abre en una pestaña nueva). Lee las preguntas frecuentes sobre los parches

Ir directamente al resumen generado por IA de esta entrada del blog

  • Resume esta entrada con Perplexity
  • Resume esta publicación con Gemini

Principales conclusiones

  • El software al final de su ciclo de vida suele seguir funcionando con normalidad, pero, una vez que dejan de publicarse parches de seguridad por parte del desarrollador original, es posible que las vulnerabilidades recién descubiertas ya no reciban un parche de dicho desarrollador.
  • Actualizar una dependencia que ha llegado al final de su ciclo de vida (EOL) rara vez consiste en un simple cambio de versión, ya que las API incompatibles, las dependencias transitivas y las pruebas de regresión pueden convertirlo en un proyecto de ingeniería de varias semanas.
  • Los archivos de bloqueo, la supervisión de dependencias y el soporte ampliado durante todo el ciclo de vida no eliminan la necesidad de realizar la migración, pero te permiten llevarla a cabo según tu propio calendario, en lugar de tener que hacerlo durante un incidente.

En el desarrollo moderno, cada «npm install» es un acto de confianza. Estás incorporando código que no has escrito tú, mantenido por personas a las que no conoces, con un calendario de soporte que nadie te ha prometido jamás. Esa confianza se viene abajo cuando una biblioteca principal, un marco de trabajo, un entorno de ejecución u otra dependencia llega al final de su vida útil (EOL).

Para un desarrollador novato, el software al final de su ciclo de vida puede parecer poco más que una molesta advertencia en un informe de dependencias. La aplicación sigue compilándose. El entorno de producción sigue funcionando. No parece que haya ningún fallo, y precisamente por eso es tan fácil subestimar el fin del ciclo de vida.

Una vez que finaliza el mantenimiento por parte del desarrollador original, también dejan de publicarse parches de seguridad para esa versión. Es posible que el software siga funcionando durante años. Sin embargo, la próxima vulnerabilidad que afecte a ese software podría no tener una solución por parte del desarrollador original, y el consejo que se suele dar —«simplemente actualízalo»— suele ser erróneo con tanta frecuencia que resulta peligroso.

La realidad de la bandera roja

Desmitificar el fin de la vida útil del software significa comprenderlo antes de que se convierta en una emergencia. El fin de la vida útil no es necesariamente un fallo técnico, ni es culpa del desarrollador que instaló el paquete. El software tiene un ciclo de vida, y los responsables de su mantenimiento, tarde o temprano, tienen que dedicar su tiempo y sus recursos a otras tareas.

La distinción que importa es la siguiente: un programa que funciona no es lo mismo que un programa con soporte técnico.

Cuando una versión llega al final de su vida útil (EOL), el proveedor o la comunidad de origen suelen dejar de publicar correcciones de seguridad para ella. Eso no significa que el código se vuelva vulnerable de la noche a la mañana. Significa que, si más adelante se descubre una vulnerabilidad que afecte a esa versión, es posible que ya no haya ningún parche disponible por parte del proveedor o la comunidad de origen. Yo lo comparo con una cerradura de la que ya nadie tiene la llave. La puerta sigue cerrada hoy, pero si mañana alguien descubre cómo forzarla, nadie de la comunidad de origen volverá para cambiarla.

También puedes leer nuestra guía completa sobre la diferencia entre «fin de vida útil» y «fin de soporte» para comprender mejor cómo las definiciones del ciclo de vida de los proveedores afectan a tu nivel de seguridad.

Detectar el fin de la vida útil antes de que te detecte a ti

Casi nada se anuncia por sí solo. Un paquete no muestra ningún aviso durante la instalación indicando que el responsable del mantenimiento aceptó un trabajo en otro sitio en 2022 y dejó de responder a las incidencias. Hay que buscarlo, y las señales de que una dependencia puede estar al final de su vida útil (EOL), en desuso o, en la práctica, sin mantenimiento suelen estar a la vista de todos:

  • Un aviso de obsolescencia en la ficha del registro, que a veces remite a un paquete sucesor y otras veces no remite a nada.
  • Una fecha de última publicación muy posterior al ritmo habitual de lanzamiento del proyecto
  • Un único responsable del mantenimiento, o una lista de responsables en la que todas las cuentas han dejado de estar activas
  • Informes de seguridad abiertos en el sistema de seguimiento de incidencias que no han recibido respuesta
  • Una tabla de compatibilidad publicada que, sin previo aviso, deja de ser válida a partir de una versión que ya habías superado hace dos lanzamientos
  • CI configurada para realizar pruebas únicamente con versiones en tiempo de ejecución que, a su vez, se encuentran en fase de fin de vida útil (EOL)

Merece la pena estar al tanto de las fechas de fin de vida útil publicadas, pero no son promesas. Node.js 16 es el ejemplo al que siempre vuelvo: su fin de vida útil estaba previsto inicialmente para abril de 2024, pero luego se adelantó siete meses, hasta el 11 de septiembre de 2023, para que coincidiera con el fin del soporte de la biblioteca OpenSSL 1.1.1 incluida en él. Los equipos que se habían decantado por Node 16 y habían previsto una migración para mediados de 2024 perdieron casi un año de margen debido a una decisión tomada en la fase de desarrollo.

Si un paquete ha quedado oficialmente obsoleto y cuenta con un sucesor concreto, empieza a planificar la migración ahora mismo, mientras no haya ninguna urgencia. Si simplemente está desactualizado pero sigue funcionando, fíjalo, añádelo a una lista de seguimiento e incluye un sustituto en la lista de tareas pendientes asignándole un responsable.

API defectuosas y pruebas de regresión

A lo largo de los años, he oído innumerables veces el viejo dicho «simplemente actualízalo». A todos nos ha pasado: al principio te vas familiarizando poco a poco con las complejidades de la producción y, a medida que vas ascendiendo a puestos de mayor responsabilidad, tu perspectiva se amplía. Los desarrolladores con experiencia saben que dejar de utilizar una biblioteca que ha llegado al final de su vida útil (EOL) rara vez es tan sencillo como cambiar un número de versión.

Una actualización importante puede conllevar cambios radicales en la API, funciones obsoletas, complementos incompatibles y nuevos requisitos de ejecución. Incluso los pequeños cambios en las dependencias pueden requerir pruebas de regresión en todos los componentes que dependen de ellas, y en una aplicación real esas pruebas pueden llevar días o semanas.

Imagina un equipo de SaaS de 40 personas que sigue utilizando esa versión base de Node 16, ya fuera de ciclo de vida. Solo el cambio de entorno de ejecución puede acarrear la recompilación de módulos nativos, un ejecutor de pruebas que ya no acepta el antiguo formato de configuración y un puñado de paquetes cuyas nuevas versiones principales han modificado el comportamiento predeterminado en lugar de las firmas de las funciones —el tipo de cambio que pasa la integración continua (CI) pero falla en producción—. En un entorno más complejo, hay que añadir la recompilación de integraciones, la validación de dependencias posteriores y la coordinación de lanzamientos entre equipos.

También puedes obtener más información sobre cómo gestionar el fin de la vida útil de un marco de trabajo heredado en nuestra guía sobre la asistencia para el fin de la vida útil de Knockout.js.

Por eso no se debe dejar que los desarrolladores noveles se enfrenten a estas complejidades por su cuenta, ni que se dejen llevar por consejos excesivamente simplistas del tipo «basta con actualizarlo». Es posible que la actualización sea, sin duda, la solución adecuada a largo plazo. Pero actualizar de forma segura es un proyecto de ingeniería, no algo que se haga con solo pulsar un botón.

Establece un plazo para un «spike» antes de que nadie se comprometa con una estimación del sprint, y trabaja en pareja. Una mejora cuyo alcance no se haya definido no es una incidencia, es una suposición.

Desviación de la dependencia transitiva

Los proyectos de software actuales son extremadamente complejos. Lo que se declara directamente en package.json, pom.xml, o requirements.txt es solo una parte de lo que finalmente acaba en la aplicación. Debajo de esas dependencias directas hay una capa tras otra de dependencias transitivas.

Un proyecto puede depender del paquete A, que a su vez depende del paquete B, el cual incluye el paquete C. Aunque nunca hayas elegido el paquete C, su código acaba formando parte de tu árbol de dependencias, y es habitual que unas pocas docenas de dependencias directas se traduzcan en cientos o miles de paquetes instalados.

Esto genera una superficie de seguridad mucho mayor de lo que sugiere la lista de dependencias de primer nivel. Una vulnerabilidad oculta a varios niveles de profundidad puede seguir siendo relevante, incluso cuando el marco que has instalado intencionadamente parece estar en perfecto estado en todos los paneles de control de los que dispones. Las herramientas modernas pueden identificar muchas de estas dependencias indirectas —el gráfico de dependencias de GitHub y Dependabot, por ejemplo, revelan dependencias transitivas vulnerables cuando pueden resolverse a partir de un manifiesto o un archivo de bloqueo—, pero los desarrolladores siguen necesitando visibilidad sobre lo que realmente se está distribuyendo.

Cuando los componentes en fin de vida útil (EOL) se incorporan a ese árbol, la corrección se complica. Es posible que sepas que existe una vulnerabilidad y que, posteriormente, descubras que la versión de la que dependes no dispone de ninguna actualización de seguridad.

Tu riesgo real en materia de dependencias no se limita a la lista de dependencias directas que figura en tu manifiesto. Se trata del árbol completo de dependencias resueltas, y eso es precisamente lo que tus herramientas de seguridad deben poder analizar.

El coste oculto de «hecho»

La definición de «terminado» puede ser un tema que dé miedo, pero es una conversación que hay que mantener al inicio de cada proyecto y que debe formar parte integrante de la política del equipo. El mantenimiento no es una tarea puntual, sino una disciplina continua.

La deuda técnica siempre existirá —ya he tenido que lidiar con ella en ocasiones anteriores—, pero las dependencias que quedan al final del ciclo de vida convierten parte de esa deuda técnica en deuda de seguridad.

Esa deuda se traduce en miles de líneas de código que, tarde o temprano, habrá que refactorizar; actualizaciones fallidas que hay que revertir; dependencias fijadas porque las versiones más recientes rompen la compatibilidad; o aplicaciones heredadas que nadie quiere tocar porque dependen de ellas demasiados sistemas. Ignorar el problema no hace que la dependencia desaparezca.

Al final, surge una vulnerabilidad crítica, un escáner empieza a detectar problemas, un auditor pregunta por qué sigue utilizándose en producción software que ya no recibe soporte, o bien otro proyecto requiere de repente una versión más reciente. Entonces, una migración que podría haberse planificado se convierte en una emergencia, y los equipos entran en pánico.

El mejor enfoque consiste en identificar con antelación el software al final de su ciclo de vida (EOL), comprender qué sistemas dependen de él y decidir de forma deliberada si se actualiza, se sustituye, se aísla o se sigue protegiendo mientras se planifica la migración. Un paquete EOL sin responsable y sin fecha prevista no es deuda técnica. Es un incidente abierto cuyo inicio se ha retrasado.

La defensa y la cúpula de armadura

Para mitigar el problema del software al final de su ciclo de vida (EOL) no basta con reaccionar ante cada CVE concreto. Es necesario tener una visión clara de lo que se utiliza, controlar lo que entra en el entorno y contar con un plan para cuando desaparezca el soporte técnico de los proveedores.

Piensa en ello como en la creación de una «cúpula de protección» en torno al ciclo de vida de tu software: reduce el riesgo de la cadena de suministro mientras los paquetes se mantienen activamente, supervisa las dependencias que ya están en producción y cuenta con una estrategia de seguridad para los componentes que sigan utilizándose tras el fin de su vida útil (EOL).

Fíjalos y bloquéalos

Un entorno de compilación determinista es una de las primeras líneas de defensa. En el caso de los proyectos de npm, guarda en el control de versiones tu archivo de bloqueo: package-lock.json – al sistema de control de versiones y utiliza npm ci en los flujos de trabajo de CI/CD cuando sea pertinente. Esto instala las versiones exactas de las dependencias registradas en el archivo de bloqueo, en lugar de resolver silenciosamente un árbol diferente en cada compilación, y da un error evidente si el archivo de bloqueo y el package.json han dejado de estar sincronizados.

Los rangos de versiones, como el símbolo de intercalación (^) y la tilde (~) siguen teniendo usos legítimos, por lo que el objetivo no es eliminarlos en todos los casos. El objetivo es comprender cómo interactúan tu política de versiones y tu archivo de bloqueo, de modo que las actualizaciones de las dependencias sean intencionadas y no accidentales. npm update, por ejemplo, respeta las restricciones de versión semántica declaradas por tu paquete y sus dependencias, lo que significa que un rango de versiones puede autorizar actualizaciones compatibles que nunca hayas aprobado individualmente.

Un detalle que suele pasar desapercibido: fijar versiones exactas en package.json solo controla tu dependencias directas . Durante una nueva resolución o una actualización de dependencias, las dependencias transitivas siguen seleccionándose según los rangos que declaren sus paquetes padres. A continuación, un archivo de bloqueo confirmado registra el árbol resuelto, y npm ci instala ese árbol bloqueado de forma reproducible. Si necesitas forzar una versión transitiva concreta, la opción campo «overrides» de npm te permite hacerlo (resoluciones en Yarn).

Si tu proyecto es una biblioteca, utiliza rangos para que los usuarios puedan eliminar duplicados. Si se trata de una aplicación desplegada, opta por versiones exactas y ciclos de actualización planificados.

La clave está en la repetibilidad. Los entornos de desarrollo, integración continua, staging y producción deben basarse en un estado de dependencias que tu equipo pueda identificar, reproducir y revisar, lo que ayuda a eliminar una de las frases más temidas en el ámbito del desarrollo: «Bueno, en mi ordenador funciona».

SCA Tooling al rescate

El análisis de la composición del software (SCA) y las herramientas de seguridad basadas en dependencias te permiten realizar un seguimiento de las vulnerabilidades con un nivel de detalle que ninguna revisión humana puede alcanzar. No solo debes saber qué paquetes has instalado deliberadamente, sino también qué otros paquetes se han instalado junto con ellos.

El gráfico de dependencias de GitHub y Dependabot pueden identificar dependencias vulnerables, tanto directas como transitivas, en los ecosistemas compatibles, y ayudar a los equipos a determinar qué aspectos deben abordarse con mayor prioridad. Del mismo modo, Snyk crea árboles de dependencias y puede recomendar vías de actualización para las dependencias indirectas vulnerables.

La detección de CVE conocidos tampoco es el único problema de la cadena de suministro. Un paquete malicioso o comprometido puede resultar peligroso mucho antes de que se le asigne un CVE. Herramientas como Socket abordan esta cuestión desde otro ángulo, supervisando los cambios en las dependencias y analizando el comportamiento de los paquetes en busca de riesgos como accesos inesperados a la red, al sistema de archivos o al shell.

Si solo vas a hacer una cosa, revisa las dependencias resueltas que tu aplicación incluye realmente y establece una política que determine qué hallazgos deben bloquear las fusiones. Si puedes ir más allá, añade un análisis de comportamiento de las dependencias nuevas y actualizadas, ya que un historial de CVE limpio no dice nada sobre un paquete que haya sido comprometido recientemente.

Una advertencia: un escáner que genere resultados que nadie evalúe puede crear una falsa sensación de cobertura. Deriva los resultados que requieran acción al responsable correspondiente y define cómo deben gestionarse.

La lección para un desarrollador novel es sencilla: saber qué entra en tu aplicación, saber por qué está ahí y saber cómo vas a detectar cuándo algo cambia.

Arnés ELS

 

En un mundo ideal, todas las dependencias que han llegado al final de su vida útil (EOL) podrían actualizarse de inmediato. Pero los entornos de producción reales no funcionan así. La migración a un nuevo marco de trabajo podría requerir reescribir parte de una aplicación. Una actualización en tiempo de ejecución podría afectar a una dependencia crítica para el negocio. Una biblioteca antigua podría estar presente en un sistema al que nadie puede tocar hasta que finalice otro proyecto dentro de seis meses.

Nada de eso hace que sea aceptable ignorar el problema de seguridad. Significa que, a veces, los equipos necesitan una opción intermedia entre «actualizar inmediatamente» y «utilizar software sin soporte técnico y sin parches de seguridad».

Ahí es donde el servicio de soporte de ciclo de vida ilimitado (ELS) entra en juego. El ELS de TuxCare proporciona parches de seguridad continuos para los sistemas operativos, entornos de ejecución, bibliotecas y aplicaciones que han llegado al final de su vida útil y que están cubiertos por el servicio, de modo que los equipos puedan mantener seguras las versiones de las que realmente dependen mientras planifican una eventual migración.

Para los paquetes de código abierto que se encuentran en fases iniciales de su ciclo de vida, SecureChain añade otra capa de seguridad. SecureChain actúa como un sustituto seleccionado de los registros públicos —npm, PyPI, Maven, Go modules, crates.io y PHP— y ofrece paquetes recompilados a partir de código fuente verificado, supervisados y parcheados de forma continua, con compatibilidad inmediata para gestores de repositorios como Artifactory, Nexus y GitHub Packages. Cuando el mantenimiento del desarrollador original llegue a su fin, ELS puede seguir proporcionando correcciones para los paquetes compatibles. En conjunto, esto te garantiza la continuidad, desde el código abierto en mantenimiento activo hasta su uso tras el fin de la vida útil (EOL).

Y lo que es más importante, ofrece un margen de maniobra a los equipos de desarrollo. En lugar de precipitarse a realizar una migración porque ha aparecido una vulnerabilidad tras finalizar el soporte del desarrollador original, se pueden planificar, probar y llevar a cabo las actualizaciones siguiendo un calendario que se adapte a las necesidades de la aplicación.

Eso no elimina la necesidad de modernizarse. Lo que elimina es la idea de que la modernización tenga que llevarse a cabo en situaciones de emergencia.

Reflexiones finales

La seguridad no caduca solo porque el soporte técnico del software sí lo haga. Con demasiada frecuencia, los equipos no prestan atención hasta que las cosas se tuercen, y entonces todo el mundo se pone a correr de un lado a otro. Tenemos que cambiar esa mentalidad.

No hace falta ser un experto en seguridad para marcar la diferencia como desarrollador. Lo que sí hay que entender es que las dependencias tienen ciclos de vida, que el código transitivo es importante, que «sigue funcionando» no significa «sigue recibiendo soporte» y que pulsar a ciegas «actualizar» tampoco es una estrategia de seguridad.

Averigua de qué depende tu aplicación. Guarda tus archivos de bloqueo. Supervisa tu árbol de dependencias. Infórmate de cuándo los componentes importantes llegan al final de su vida útil (EOL) y prepara una estrategia de actualización antes de que la necesites desesperadamente. Cuando una migración inmediata no sea viable, asegúrate de que el software sin soporte técnico no se quede simplemente en producción sin una fuente de parches de seguridad.

Empieza con algo sencillo esta semana: abre tu archivo de control de versiones, busca el paquete más antiguo que haya en él y comprueba cuándo se publicó por última vez. Tanto si eres un desarrollador novel como un arquitecto principal, ese hábito te ayudará mucho a proteger tu pila de aplicaciones y a evitar que llegue el día en que una dependencia olvidada se convierta en el mayor problema de todos.

Resumen
Software al final de su ciclo de vida: lo que nadie les cuenta a los desarrolladores noveles
Nombre del artículo
Software al final de su ciclo de vida: lo que nadie les cuenta a los desarrolladores noveles
Descripción
El software al final de su ciclo de vida sigue funcionando hasta que aparece la siguiente vulnerabilidad CVE para la que no hay parche. Descubre qué significa «EOL» para tus dependencias y cómo mantener la seguridad.
Autor
Nombre del editor
TuxCare
Logotipo de la editorial

Únase a más de 4.500 profesionales de Linux y el código abierto.

2 veces al mes. Sin spam.

Índice
Obtenga las respuestas de seguridad de código abierto que necesita

Únase a más de 4.500 profesionales de Linux y el código abierto.

2 veces al mes. Sin spam.