Ir al contenido

Cuando la confianza es la vulnerabilidad

Autor
Hernan Rocca
Escribo sobre lo que perdura cuando pasa el ruido, mi pasión… el código, la arquitectura e IA aplicada.

Quiero arrancar con una confesión que probablemente compartan muchos de los que lean esto: no tengo la menor idea de qué hay, exactamente, dentro de la mayoría del software que uso para construir software. Cuando arranco un proyecto y corro ese comando que instala dependencias, en segundos se descargan decenas, a veces cientos de paquetes, escritos por gente que no conozco, que a su vez dependen de otros paquetes escritos por otra gente que tampoco conozco, en una cadena que se hunde varios niveles más abajo de lo que jamás voy a inspeccionar. Y lo acepto. Todos lo aceptamos. Es la única forma de trabajar a la velocidad que el mundo nos exige. Confiamos, sin pensarlo demasiado, en una cantidad asombrosa de código ajeno. Este mes, un ataque al ecosistema de paquetes de JavaScript me hizo volver a mirar esa confianza de frente, y entender, una vez más, que lo que nos permite avanzar rápido es exactamente lo mismo que nos vuelve frágiles. Quiero pensar en voz alta sobre eso, no desde la seguridad técnica —que no es mi especialidad— sino desde algo que sí me ocupa todos los días: las dependencias que aceptamos sin mirar, y la confianza sobre la que está construido todo.

Lo que pasó, en términos simples
#

A mediados de septiembre, el ecosistema de npm —el gigantesco repositorio de paquetes sobre el que se construye buena parte del software JavaScript del mundo— sufrió un ataque que llamó mucho la atención, y no tanto por su tamaño como por su forma. Apareció un código malicioso, que los investigadores bautizaron con un nombre sacado de la ciencia ficción, Shai-Hulud, con una característica novedosa: se replicaba solo. No era un único paquete envenenado, esperando que alguien lo descargara. Era algo que, una vez dentro de un entorno, buscaba credenciales, las robaba, y las usaba para infectar otros paquetes y seguir propagándose por su cuenta, como un gusano. El primero de su tipo en ese ecosistema.

La puerta de entrada, y este es el detalle más revelador de todos, no fue una vulnerabilidad técnica sofisticada. Fue un engaño. Los atacantes montaron una campaña de correos falsos, imitando al sitio oficial de npm con un dominio que se le parecía mucho, y le pidieron a los mantenedores de paquetes que “actualizaran” su segundo factor de autenticación. Algunos cayeron, entregaron sus credenciales, y con eso los atacantes pudieron publicar versiones maliciosas de paquetes legítimos, populares, en los que miles de proyectos confían. Entre los afectados hubo bibliotecas muy usadas. No hizo falta romper ninguna cerradura sofisticada: alcanzó con convencer a alguien de que entregara la llave.

No me interesa entrar en los detalles técnicos del ataque —hay gente que sabe muchísimo más que yo sobre eso, y ya escribió análisis excelentes—. Me interesa el patrón, porque el patrón es el que perdura cuando este incidente puntual quede olvidado. Y el patrón es viejo, mucho más viejo que npm: atacar el eslabón de confianza en lugar de atacar la fortaleza.

La montaña de confianza sobre la que estamos parados
#

Damos por sentado, sin pensarlo nunca, que el software moderno se construye sobre una base de confianza descomunal. Cada vez que sumamos una dependencia a un proyecto, estamos confiando en mucha gente a la vez: en quien escribió ese paquete, en que no metió nada malicioso, en que lo mantiene con cuidado, en que su cuenta no fue comprometida, en que las dependencias de su paquete son igual de confiables, y así hacia abajo, niveles y niveles de confianza encadenada que nadie verifica en su totalidad porque sería, literalmente, imposible.

Esto no es un defecto del sistema; es el sistema. La razón por la que hoy podemos construir en semanas cosas que antes llevaban años es justamente que no tenemos que escribir todo desde cero. Nos paramos sobre el trabajo de miles de personas que resolvieron, antes que nosotros, problemas que ya no necesitamos volver a resolver. El código abierto, el ecosistema de paquetes compartidos, esa enorme biblioteca común de la humanidad técnica, es una de las cosas más extraordinarias que produjo nuestra industria. Y funciona, fundamentalmente, porque confiamos. La confianza es el combustible que hace que todo esto ande.

Pero acá está el filo de la navaja, y es lo que el ataque de este mes vuelve a poner sobre la mesa: esa misma confianza, que es nuestra mayor fortaleza, es también nuestra mayor vulnerabilidad. Cada relación de confianza es un camino. Y un camino que sirve para que nos llegue valor sirve, exactamente igual, para que nos llegue daño. No se puede tener uno sin el otro. La apertura que nos permite recibir lo bueno es la misma apertura por la que puede entrar lo malo. No hay una versión del sistema que conserve toda la velocidad y elimine todo el riesgo, porque la velocidad y el riesgo vienen, en buena medida, de la misma fuente.

Atacar la confianza, no la fortaleza
#

Lo que más me quedó dando vueltas de este incidente es que el ataque no fue contra la tecnología, sino contra la confianza. Los atacantes no encontraron una falla brillante en el código de npm; encontraron a una persona y la engañaron. Y eso conecta con algo que escribí hace más de un año, cuando hablé de la caída asociada a CrowdStrike: que el riesgo tecnológico no siempre tiene un atacante del otro lado, y que muchas veces el problema no es la fortaleza de nuestros muros sino la cantidad de puertas que ni sabíamos que teníamos abiertas.

Acá hay un atacante, sí, pero la lógica es parecida. El eslabón más débil de una cadena de confianza casi nunca es el más técnico; es el más humano, el más descuidado, el que confiábamos tanto que dejamos de mirar. Una cuenta de un mantenedor que reutilizó una contraseña. Una persona apurada que hizo clic en un correo que parecía legítimo. Un paquete que usábamos hace años y que nunca nos dio problemas, y que por eso mismo dejamos de vigilar. El atacante inteligente no va contra lo que está bien protegido; va contra lo que damos por seguro justamente porque nunca falló. La confianza acumulada, no cuestionada, es la superficie de ataque más grande y la peor mapeada que tenemos.

La paradoja del paquete que nunca falló
#

Hay una idea que vengo repitiendo en varios posts y que este ataque vuelve a confirmar desde otro ángulo: las dependencias más confiables son, por eso mismo, las que peor vigilamos. Cuanto mejor funciona un paquete, más invisible se vuelve. Lo instalamos una vez, anduvo, y a partir de ahí dejó de existir en nuestra cabeza. Pasó a ser parte del paisaje, como el aire. Y cuando algo se vuelve invisible, deja de ser objeto de atención, de revisión, de sospecha sana.

El ataque de este mes explotó exactamente eso. Las versiones maliciosas se publicaron sobre paquetes legítimos y populares, paquetes en los que la gente confiaba precisamente porque tenían un largo historial de comportarse bien. Nadie revisa con lupa la nueva versión de una biblioteca que viene funcionando impecablemente desde hace años; la actualizamos casi por reflejo, porque siempre estuvo todo bien. Esa actualización automática, ese reflejo de confiar en lo que nunca falló, fue el vector. La confiabilidad histórica se convirtió en la herramienta del ataque. Y esto debería darnos que pensar más allá de npm, porque el patrón es universal: en toda organización hay piezas, internas y externas, que dejamos de mirar precisamente porque nunca nos dieron un problema. Su buen comportamiento se transformó, sin que lo decidiéramos, en una excusa para la complacencia.

No se trata de desconfiar de todo
#

Ahora bien, sería fácil sacar de todo esto la conclusión equivocada: desconfiemos de todo, revisemos cada línea de cada dependencia, volvamos a escribir todo desde cero. Eso sería absurdo, además de imposible. Nadie puede auditar las cientos de dependencias de un proyecto moderno, y una organización que intentara hacerlo se paralizaría y perdería frente a las que siguen avanzando. La desconfianza total no es una estrategia; es una forma de suicidio competitivo. El valor de apoyarnos en el trabajo de otros es demasiado grande como para renunciar a él por miedo.

La respuesta madura, creo, no está en desconfiar de todo ni en confiar ciegamente, sino en un lugar incómodo del medio: confiar, pero de manera consciente y gestionada. Saber de qué dependemos, aunque no podamos auditarlo todo. Tener idea de cuáles de nuestras dependencias son críticas y cuáles son accesorias, porque no todas merecen el mismo nivel de cuidado. Entender que actualizar no es un acto neutro y gratuito, sino una decisión que introduce algo nuevo en lo que confiamos. Tener mecanismos para reaccionar rápido cuando algo se descubre comprometido, porque algo, tarde o temprano, se va a descubrir comprometido. No es eliminar la confianza; es dejar de tratarla como si fuera gratis e infinita.

La velocidad tiene un costo que no figura en la factura
#

Hay algo que conecta este tema con cosas que vengo pensando hace meses sobre la velocidad. Todo el ecosistema de paquetes está optimizado para ir rápido: instalar en segundos, actualizar sin fricción, sumar una dependencia con un solo comando. Esa velocidad es maravillosa, y nadie quiere renunciar a ella. Pero tiene un costo que no aparece en ningún lado en el momento, igual que el costo energético de un modelo de IA no aparece en el dashboard: el costo de la superficie de confianza que vamos acumulando sin darnos cuenta.

Cada dependencia que sumamos por comodidad, cada actualización que aceptamos sin mirar, cada herramienta que conectamos “porque es más rápido”, agranda un poquito la cantidad de cosas en las que confiamos sin verificar. Individualmente, cada decisión parece inofensiva, casi trivial. Acumuladas, construyen una exposición que solo se vuelve visible el día que algo falla. Es la misma lógica de la deuda: cada atajo es chiquito, pero la suma de atajos, con el tiempo, se vuelve una cuenta que alguien tiene que pagar. Y como en toda deuda, el problema no es tomarla —a veces tiene todo el sentido del mundo— sino tomarla sin saber que la estamos tomando, sin registrarla, sin tener idea de cuánto debemos.

Y ahora le sumamos agentes a la ecuación
#

Hay un giro que no quiero dejar pasar, porque conecta este tema con algo que vengo siguiendo todo el año. Hasta acá hablé de la confianza que extendemos como personas: nosotros sumamos una dependencia, nosotros aceptamos una actualización, nosotros hacemos clic en el correo. Pero estamos entrando en una etapa en la que cada vez más de esas decisiones las toman agentes de IA que trabajan por nosotros. Un agente que explora un repositorio, instala dependencias, corre comandos y resuelve una tarea de punta a punta está, sin que lo pensemos demasiado, extendiendo confianza en nuestro nombre, a una velocidad y una escala que ninguna persona podría igualar.

Cuando escribí sobre los agentes que empiezan a trabajar de verdad, insistí en que la capacidad había crecido y que por eso las barandas importaban más, no menos. Este ataque le agrega una dimensión concreta a esa idea. Si un agente instala paquetes por su cuenta, ¿qué pasa cuando uno de esos paquetes está comprometido? Si un agente tiene acceso a credenciales para hacer su trabajo, ¿qué superficie nueva estamos abriendo? La confianza implícita de la cadena de suministro, que ya era enorme cuando la gestionábamos nosotros a mano, se multiplica cuando le sumamos automatización que decide rápido y a escala. No es que los agentes inventen el problema; es que lo amplifican, porque hacen más rápido y más seguido exactamente eso que ya era riesgoso: confiar sin verificar.

No traigo esto para asustar, sino porque me parece el lugar exacto donde dos hilos del año se cruzan. Por un lado, los agentes que ejecutan acciones reales en nuestros sistemas. Por el otro, una cadena de suministro que se sostiene sobre confianza y que acaba de demostrar lo frágil que puede ser esa confianza. Juntar las dos cosas sin pensarlo —darle a un agente autónomo las llaves para sumar dependencias, instalar, ejecutar, sin límites ni registro— es combinar dos formas de confiar de más en un mismo movimiento. Y la respuesta, otra vez, no es prohibir ninguna de las dos, sino la misma de siempre: conciencia, límites, trazabilidad. Saber qué le permitimos a un agente, qué puede tocar, qué confianza está extendiendo por nosotros mientras nosotros miramos para otro lado. El arnés del que hablé en mayo y la confianza gestionada de la que hablo hoy son, en el fondo, la misma idea aplicada a dos caras del mismo problema.

No soy un experto en seguridad, y este post no pretende serlo. Pero sí soy alguien que decide, todos los días, sobre qué construir y sobre qué apoyarse, y desde ese lugar el ataque de este mes me deja algunas cosas. La primera es un recordatorio de humildad: dependemos de muchísimo más de lo que controlamos, y fingir lo contrario no nos hace más seguros, solo más ciegos. Reconocer la magnitud de nuestra confianza es el primer paso para gestionarla con algo de criterio.

La segunda es que la conversación sobre dependencias y confianza no debería ser solo un tema de los equipos de seguridad, relegado a un rincón especializado. Es una conversación de cultura técnica, de criterio, de cómo decidimos qué incorporar y qué no, de cuándo vale la pena la comodidad de sumar algo y cuándo no. Esas decisiones las tomamos todos, todo el tiempo, muchas veces sin pensarlas como decisiones. Hacerlas un poco más conscientes —preguntarnos, aunque sea un segundo, qué confianza nueva estamos extendiendo cada vez que sumamos algo— ya es un avance enorme respecto de la inercia de sumar por sumar.

Y la tercera, la que más me importa, es una idea que excede al software y que me parece el verdadero residuo perdurable de todo esto. En cualquier sistema complejo —técnico, humano, organizacional— la confianza es lo que lo hace funcionar y, al mismo tiempo, su punto más delicado. No podemos vivir sin confiar; sería paralizante e inhumano. Pero la confianza que dejamos de cuidar, que damos por sentada, que tratamos como si fuera infinita y gratuita, es exactamente la que algún día nos va a costar caro. No porque confiar esté mal, sino porque confiar sin conciencia es, en el fondo, no haber pensado en quién tiene las llaves de nuestra casa.

Les dejo una pregunta para que la lleven a su propio terreno, porque seguro tienen su propia montaña de dependencias sin mirar. Si tuvieran que nombrar las piezas de software, los proveedores o los servicios en los que su sistema confía ciegamente —esos que nunca revisan justamente porque nunca fallaron—, ¿cuántos podrían nombrar, y cuántos descubrirían recién el día en que uno de ellos deje de merecer esa confianza? Porque la confianza que no se mira no desaparece. Solo espera, en silencio, el día en que alguien decida aprovecharla.

Fuentes consultadas
#

Relacionados

Las dependencias que no sabíamos que teníamos

Toda organización conoce sus dependencias visibles: la base de datos, la nube, el sistema de pagos. El problema son las invisibles, las que nadie anotó en ningún diagrama y que descubrimos recién cuando se caen. Mapearlas no es una tarea técnica más: es la base de cualquier resiliencia real, porque no se puede proteger ni recuperar lo que no se conoce.

El mito del 10x: por qué el mejor del equipo no siempre es el que más produce

Vivimos enamorados del programador 10x, esa figura que produce como diez. Pero después de muchos años liderando equipos, aprendí que el rendimiento de un equipo no es la suma de los rendimientos individuales, y que muchas veces la persona más valiosa no es la que más código escribe. Apoyándome en algunas ideas de CEO Excellence, quiero discutir por qué el foco debería correrse de qué hace cada uno hacia cómo trabajamos juntos.

Después del vibe coding: qué quedó y qué se cayó

En marzo escribí sobre el vibe coding en pleno auge. Cuatro meses después, con el ruido más bajo, se puede empezar a separar lo que era hype de lo que era señal. La idea perdurable: las modas técnicas no son ni la revolución que prometen ni el fraude que denuncian sus críticos; dejan un residuo útil cuando una tiene la paciencia de esperar a que baje la espuma.