Instalar una dependencia parece una operación local: se escribe un nombre, un gestor descarga archivos y la aplicación compila. En realidad se ha delegado código ejecutable a un resolvedor, uno o varios registros, mantenedores externos, scripts de instalación, una toolchain y la infraestructura que publica el resultado. La pregunta de seguridad no es sólo «¿qué versión usamos?», sino qué bytes entraron, quién podía cambiarlos, qué proceso produjo el artefacto y qué evidencia permite decidir si ese artefacto exacto puede desplegarse.
La cadena de suministro de software no es una metáfora. Es una secuencia de transformaciones y autoridades. Un commit no es un paquete; un paquete no es el archivo que llegó; ese archivo no es la imagen construida; una etiqueta de imagen no es el manifest digest; una firma no demuestra que el código sea seguro. El rigor empieza por conservar esas diferencias.
Cinco identidades que no deben colapsarse
Un producto suele aparecer bajo un solo nombre humano, pero atraviesa identidades distintas:
- Fuente. Repositorio, revisión o tree digest que identifica el material editable.
- Coordenada de paquete. Ecosistema, namespace, nombre y versión, por ejemplo
pkg:npm/acme/[email protected]. - Distribución. Archivo o manifest descargado, identificado de forma estable por un digest criptográfico.
- Artefacto de build. Binario, bundle, paquete o imagen producido a partir de fuentes, dependencias, toolchain y parámetros.
- Instancia desplegada. Objeto que una plataforma ejecuta y cuya configuración puede diferir del artefacto publicado.
El nombre [email protected] ayuda a resolver, pero no prueba qué bytes se recibieron. Una etiqueta como service:stable puede apuntar mañana a otro manifest. Un commit SHA identifica una revisión en un sistema concreto, pero no acredita que la build publicada provenga de ella. El control robusto termina en digests de contenido y conserva enlaces verificables entre cada objeto.
Esta separación evita investigaciones falsas. Si aparece una vulnerabilidad en una versión nominal, hay que saber qué artefactos la incorporaron. Si se compromete el registro, hay que identificar qué descargas ocurrieron durante la ventana. Si se compromete el builder, conocer el commit no basta: la salida pudo alterarse después de leerlo.
Vista adaptada. Toca el diagrama para ampliarlo.
La cadena no convierte automáticamente una identidad en la siguiente. El resolvedor selecciona distribuciones; el builder transforma entradas; el gate verifica evidencias; el despliegue debe conservar el digest aprobado. Cada flecha es una frontera que puede fallar o ser manipulada.
El grafo real de dependencias
Una dependencia directa aparece en el manifiesto del proyecto. Una transitiva llega porque otra la requiere. Las transitivas suelen superar en número a las directas y pueden cambiar cuando el resolvedor encuentra una combinación nueva. Además existen dependencias de build, test, runtime, plugins, imágenes base, acciones de CI, compiladores y herramientas de empaquetado. «No está en producción» no puede inferirse de que aparezca bajo una sección llamada desarrollo: un plugin de build puede ejecutar código con credenciales y alterar la salida.
El grafo también cambia por plataforma, arquitectura, flags, features y dependencias opcionales. Dos instalaciones que leen el mismo manifiesto pueden resolver grafos distintos si su entorno o índice difiere. Por eso el inventario debe declarar el contexto que lo produjo.
Los nombres introducen riesgos propios. Typosquatting ocupa una grafía parecida; dependency confusion hace que un resolvedor elija un paquete público cuando se esperaba uno privado; el secuestro de una cuenta legítima publica una versión maliciosa bajo el nombre correcto. Un namespace interno sólo es seguro si la configuración de resolución impide mezclar fuentes de confianza con reglas ambiguas.
Una política mínima declara registros autorizados por scope, bloquea fallbacks inesperados, autentica publicación y consumo, registra propietarios y revisa paquetes abandonados. NIST SSDF PW.4 exige seleccionar, mantener y verificar componentes reutilizados durante su ciclo de vida; no limita la tarea al primer install.
La identidad necesaria para correlacionar vulnerabilidades tampoco es sólo un string. El mismo nombre puede existir en varios ecosistemas, una distribución puede aplicar parches sin cambiar la versión upstream y un fork puede conservar el nombre mientras modifica el código. Identificadores como Package URL ayudan a expresar tipo, namespace, nombre, versión y qualifiers, pero el resultado de matching sigue necesitando evidencia del artefacto. Un scanner que une por semejanza de nombre puede producir falsos positivos; uno que sólo busca el manifiesto puede omitir una biblioteca vendorizada.
Conviene distinguir presencia, alcance y explotabilidad. Presencia indica que el componente aparece en el inventario definido. Alcance pregunta si quedó en el artefacto o participa en build. Explotabilidad requiere configuración, ruta de ejecución y precondiciones. Una VEX puede comunicar el análisis de estado, pero no debe usarse como excepción eterna: necesita sujeto, vulnerabilidad, justificación, autoridad y fecha de revisión.
Manifiesto, resolvedor, lockfile y registro
El manifiesto expresa intención: rangos compatibles, features y dependencias declaradas. El resolvedor aplica reglas del ecosistema para elegir un grafo concreto. El registro ofrece metadata y distribuciones. El lockfile captura el resultado resuelto con el detalle que permita el formato: versiones exactas, URLs, integridad y grafo.
Estas piezas responden preguntas diferentes. Un rango ^2.4 no identifica una distribución. Una versión exacta tampoco identifica bytes si el repositorio permite reemplazos o si se descarga desde una URL mutable. Un lockfile reduce variación, pero no prueba que la selección sea benigna, que el registro no estuviera comprometido o que todos los instaladores lo respetaran.
En npm, package-lock.json describe un árbol exacto y puede incluir resolved e integrity. El modo npm ci exige coherencia con el manifiesto y no reescribe el lockfile. Esa conducta aporta repetibilidad de resolución dentro de npm, no procedencia completa de la build. Otros ecosistemas tienen contratos diferentes; copiar el término «lockfile» no copia sus garantías.
Un flujo defendible usa instalación congelada en un entorno limpio, rechaza cambios implícitos al lockfile, verifica integridad contra valores revisados y conserva el lockfile como entrada versionada. También registra el cliente y su versión: cambiar el resolvedor puede cambiar selección, layout o scripts.
Hash: mismos bytes respecto de una expectativa
Un digest criptográfico permite comprobar que dos secuencias de bytes coinciden con probabilidad práctica muy alta. Si se espera sha256:X y el archivo produce otro digest, hubo corrupción, sustitución o una expectativa errónea. Esto es integridad respecto de un valor esperado.
El hash no explica de dónde salió esa expectativa. Si atacante y archivo llegan por el mismo canal, puede sustituir ambos. Tampoco identifica al autor, revisa código ni autoriza una versión. «El checksum coincide» sólo es una conclusión útil cuando se sabe quién publicó el digest, por qué se confía en ese canal y a qué objeto exacto aplica.
Los digests deben acompañar a objetos inmutables. Promocionar una imagen por tag y verificar después el tag vuelve a resolver una referencia mutable. El gate debe obtener el manifest digest, verificar sus evidencias y entregar ese mismo digest al entorno de despliegue.
Firma: autenticidad dentro de una política de confianza
Una firma válida demuestra que una clave produjo una firma sobre un payload y que éste no cambió. Para convertirlo en una decisión de confianza faltan preguntas: ¿qué identidad controla la clave?, ¿quién certificó esa identidad?, ¿estaba autorizada a firmar este artefacto?, ¿en qué momento?, ¿fue revocada?, ¿qué campos quedaron dentro del payload?
Sigstore permite firmas basadas en identidad: Fulcio vincula una clave efímera a una identidad OIDC y Rekor registra el evento de forma auditable. Al verificar con Cosign no basta ejecutar un comando genérico; se restringen certificate-identity y certificate-oidc-issuer, y se comprueba que el digest del artefacto coincide con el payload. Una firma de cualquier workflow válido no equivale a la firma del workflow de release autorizado.
La transparencia ayuda a detectar usos inesperados de una identidad, pero requiere monitoreo. Registrar una firma maliciosa no la deshace. Una firma auténtica también puede envolver malware si la cuenta, workflow o builder autorizado fue comprometido. La conclusión correcta es «estos bytes fueron firmados bajo esta identidad y este sistema de confianza», no «estos bytes son seguros».
La build es una ejecución privilegiada
Construir software ejecuta compiladores, scripts, macros, plugins y generadores. Puede leer la red, el filesystem y variables de entorno. Si una dependencia hostil ejecuta un postinstall, el daño puede ocurrir antes de que el artefacto llegue a producción: robo de tokens, alteración de caches o publicación de otra salida.
Una build madura trata sus entradas como no confiables y reduce autoridad:
- runner efímero y limpio;
- identidad distinta por proyecto y etapa;
- secretos ausentes salvo el mínimo necesario y nunca accesibles a pasos arbitrarios;
- red deshabilitada o restringida después de adquirir entradas verificadas;
- fuentes, dependencias, imagen del builder y toolchain fijadas por digest;
- outputs nuevos, sin reutilizar un workspace contaminado;
- logs y metadata sin secretos;
- firma y procedencia generadas por la plataforma, no por el script controlado por el repositorio.
Los caches merecen una frontera propia. Ahorran tiempo, pero mezclan ejecuciones y pueden reintroducir objetos que ya no corresponden al lockfile o a la política actual. La clave de cache debe incorporar entradas relevantes; restaurar no implica confiar. Cuando una build privilegiada puede escribir una cache que otra consumirá, existe un canal entre identidades. Para releases sensibles se verifica contenido al restaurar, se segmenta por trust domain y se permite invalidación masiva tras un incidente.
Los secretos son otro problema de causalidad. Una build que sólo necesita descargar dependencias no debería poseer credenciales de publicación. La publicación puede ser una etapa posterior que recibe un digest y usa una identidad breve, acotada al repositorio y al release. Así, comprometer un compilador no concede automáticamente la capacidad de reemplazar artefactos o firmar procedencia como plataforma.
SLSA 1.2 organiza el track de build en niveles. Build L1 exige procedencia; puede ser incompleta o no firmada. L2 exige una plataforma hospedada que genere y autentique procedencia. L3 añade una plataforma endurecida que aísla ejecuciones y evita que pasos definidos por el usuario accedan al material que autentica procedencia. El nivel describe requisitos bajo un modelo de amenazas; no certifica ausencia de vulnerabilidades.
Hermética y reproducible tampoco son sinónimos. Una build hermética sólo usa entradas declaradas y controladas en su frontera; puede seguir incluyendo timestamps aleatorios y producir bytes distintos. Una build reproducible permite que otra parte, con la misma fuente, entorno e instrucciones definidos, obtenga artefactos idénticos bit a bit. Puede ser reproducible y maliciosa si las entradas ya lo eran.
Reproducibilidad: una comparación, no una procedencia completa
Reproducible Builds define la propiedad con tres conjuntos: código fuente, entorno e instrucciones. Otra parte debe recrear copias bit a bit de los artefactos especificados. Los timestamps, locale, zona horaria, orden de archivos, rutas de build y aleatoriedad suelen romperla.
Cuando una reconstrucción independiente coincide con el digest distribuido, aporta evidencia de que ese artefacto es consecuencia del conjunto declarado. No prueba por sí sola que el repositorio era el oficial, que el compilador era confiable, que la fuente era segura ni que todas las personas pueden repetir el proceso. La independencia del rebuilder y la autenticidad de sus entradas importan.
La reproducibilidad permite detectar alteraciones del builder y facilita múltiples verificadores. Su valor crece cuando la especificación del entorno es precisa y archivada. Si las dependencias desaparecen o un contenedor base sólo se conserva por tag, la afirmación puede volverse imposible de volver a comprobar.
SBOM: inventario con alcance y momento
Una Software Bill of Materials enumera componentes y relaciones de un objeto. SPDX 3.0.1 y CycloneDX 1.7 permiten representar componentes, identificadores, hashes, licencias y relaciones con distintos modelos. El formato es importante para interoperar; la calidad depende de cómo, cuándo y sobre qué sujeto se generó.
Un SBOM de fuente observa dependencias declaradas. Uno de build puede capturar lo que entró al proceso. Uno del artefacto analiza lo que quedó empaquetado. Ninguno es necesariamente idéntico a los otros. Dependencias eliminadas por tree-shaking pueden aparecer en el lockfile pero no en el bundle; librerías copiadas manualmente pueden aparecer en el binario sin estar en el manifiesto.
Para que un SBOM sea operativo necesita:
- ligarse al digest del artefacto exacto;
- declarar herramienta, versión, etapa y timestamp;
- conservar identificadores de paquete y relaciones;
- representar componentes desconocidos o no resueltos en vez de omitirlos;
- regenerarse cuando cambia el artefacto;
- protegerse y distribuirse con autenticidad.
Un SBOM no demuestra que los componentes son seguros, que el inventario es completo, que una vulnerabilidad es alcanzable ni que el binario se construyó con lo listado. Permite consultar y correlacionar. El análisis de vulnerabilidades necesita feeds actuales, matching correcto de ecosistema y versión, y después contexto de alcance y explotación.
Procedencia y attestations: afirmaciones sobre un sujeto
SLSA usa provenance para describir dónde, cuándo y cómo se produjo un artefacto. La procedencia de build enlaza el output con el proceso y sus materiales; la de fuente describe cómo se creó una revisión. No son intercambiables.
El Attestation Framework de in-toto separa cuatro capas. El predicate contiene metadata con semántica propia; el statement lo liga a uno o varios sujetos y declara predicateType; el envelope autentica; un bundle agrupa attestations. En un statement v1, cada sujeto necesita digest. Esa unión evita que una afirmación sobre app.tar se aplique a otro archivo con el mismo nombre.
Una attestation es una afirmación autenticada, no una verdad automática. El consumidor debe comprender su predicate type, verificar el envelope, comparar el subject digest y evaluar quién la produjo. Una procedencia firmada por un builder no aprobado puede ser criptográficamente válida y políticamente inútil. Una procedencia correcta puede declarar que se construyó desde una rama no autorizada.
Vista adaptada. Toca el diagrama para ampliarlo.
La separación importa durante un incidente. El hash responde «¿son los mismos bytes?». La firma, «¿qué identidad autenticó esta afirmación?». El SBOM, «¿qué componentes se declaran o detectan?». La procedencia, «¿qué proceso y materiales se afirman?». La reproducción, «¿otra build controlada obtuvo los mismos bytes?». La política combina respuestas y conserva incertidumbres.
El gate de promoción
Promover no es copiar una etiqueta de staging a production. Es autorizar un digest inmutable después de evaluar evidencia contra una política versionada.
Un gate útil recibe el digest candidato y verifica, en orden:
- Sujeto. Firma, SBOM y procedencia se refieren al mismo digest candidato.
- Autenticidad. Cadena de confianza, issuer, identidad y transparencia son válidos.
- Productor autorizado. El workflow, repositorio, ref y builder pertenecen a la política de ese producto.
- Proceso. La procedencia incluye materiales esperados y no declara parámetros prohibidos.
- Fuente. La revisión fue creada por el proceso de cambio requerido y corresponde a la release.
- Inventario. El SBOM tiene alcance y frescura suficientes; componentes prohibidos se rechazan.
- Riesgo. Hallazgos y vulnerabilidades se evalúan con una excepción explícita, propietaria y expirable, no con un silencio.
- Resultado. El sistema promociona y despliega exactamente ese digest; no vuelve a resolver un tag.
Vista adaptada. Toca el diagrama para ampliarlo.
La evaluación debe fallar cerrada cuando falta evidencia obligatoria, pero distinguir ausencia de incumplimiento. «No hay SBOM» y «el SBOM contiene un componente prohibido» exigen respuestas distintas. Las excepciones deben ser objetos auditables con motivo, alcance, aprobador y caducidad.
Separar funciones reduce impacto. El autor no debería poder aprobar su propio cambio, modificar el builder, emitir procedencia y alterar la política de promoción con una sola identidad. Las claves o identidades de release no deben estar disponibles durante pasos controlados por el repositorio.
La política también debe estar versionada y protegida. Si un atacante puede relajarla en el mismo cambio que introduce el artefacto, el gate sólo automatiza la aprobación del atacante. Los cambios de política requieren propietarios distintos, revisión y una ruta de emergencia explícita. Registrar el hash de la política evaluada permite reconstruir por qué una release fue aceptada, incluso si las reglas cambian después.
Un resultado de verificación debe conservar evidencia negativa y contexto: qué regla falló, qué documento faltó, qué versión del verificador se usó y cuál era el tiempo confiable. Guardar sólo approved=true elimina la capacidad de auditar. Tampoco conviene copiar ciegamente todas las attestations al runtime; el plano de control puede conservar el expediente y emitir una decisión firmada con sujeto, política y propiedades verificadas.
Distribución y actualización
La confianza continúa después de construir. Un mirror comprometido puede servir versiones antiguas correctamente firmadas. Una firma sin metadata de versión y expiración no evita rollback ni freeze.
The Update Framework distribuye responsabilidades entre roles de root, targets, snapshot y timestamp, permite thresholds y expiraciones, y diseña la actualización para resistir compromisos parciales. Root establece claves y roles; targets describe artefactos; snapshot fija conjuntos coherentes de metadata; timestamp señala frescura. El cliente mantiene estado confiable y rechaza versiones de metadata regresivas.
No todos los productos necesitan implementar TUF directamente, pero toda estrategia de actualización debe responder: ¿cómo rota la raíz?, ¿cómo se revoca una identidad?, ¿cómo detecta rollback?, ¿cómo expira metadata?, ¿cómo impide mezclar archivos de releases distintas?, ¿cómo se recupera si una clave online cae?
Caso trabajado: paquete comprometido
Un equipo publica billing-api:4.8.0. El manifiesto permite serializer ^3.2; el lockfile fija 3.2.7 y registra un digest. La build corre en un runner hospedado, sin red tras descargar un conjunto verificado. La plataforma genera procedencia SLSA y firma la imagen. Un SBOM de artefacto se liga al manifest digest. El gate acepta sólo la identidad del workflow de release en la rama protegida.
Días después se descubre que la cuenta del mantenedor de serializer fue secuestrada y que 3.2.7 contiene un script de instalación que exfiltra variables del runner. «La aplicación no importa esa función» no descarta el incidente: el script ya se ejecutó durante build.
La respuesta empieza congelando nuevas promociones, no borrando evidencias. Se identifica el digest exacto del paquete, se consulta qué builds lo usaron y se localizan imágenes mediante SBOM y procedencia. Se revisa si el runner exponía secretos, red y caches compartidos. Los secretos accesibles se rotan; las identidades de firma sólo se rotan si el adversario pudo usarlas, pero se examina el log de transparencia en cualquier caso.
El equipo fija una versión limpia por digest, invalida caches contaminados y reconstruye en runners nuevos. Compara los outputs y genera SBOM, procedencia y firmas nuevas. La promoción referencia el digest reconstruido; cambiar latest no repara despliegues fijados ni demuestra que el objeto anterior dejó de ejecutarse. El inventario de runtime confirma el retiro.
Si sólo existiera un lockfile, podría saberse qué versión se pretendía instalar, pero no qué builds la usaron. Si sólo existiera un SBOM, habría inventario, pero quizá no proceso ni builder. Si sólo hubiera firma, se conocería una identidad de publicación sin materiales. La investigación funciona porque las evidencias se complementan y comparten un sujeto estable.
Método de revisión
Para cada producto y artefacto, completa esta ficha:
- Objeto. ¿Qué fuente, distribución, artefacto y despliegue se identifican? ¿Cuáles son sus digests?
- Resolución. ¿Qué manifiesto, lockfile, resolvedor y registros determinan el grafo?
- Autoridad. ¿Quién puede publicar paquetes, cambiar dependencias, modificar builders, firmar y promover?
- Build. ¿Qué entradas, red, secretos, caches, toolchain y aislamiento existen?
- Inventario. ¿El SBOM es de fuente, build o artefacto? ¿Está ligado al subject digest?
- Procedencia. ¿Quién afirma el proceso? ¿La firma y el predicate type son válidos? ¿Qué queda fuera?
- Reproducción. ¿Otra parte puede reconstruir? ¿Qué variaciones siguen sin fijar?
- Política. ¿Qué issuer, identidad, repositorio, ref, builder y materiales son aceptables?
- Actualización. ¿Cómo se evita rollback, freeze y mezcla de releases?
- Incidente. ¿Puede localizarse cada uso, revocar confianza, reconstruir y verificar retirada?
Una respuesta como «tenemos SBOM» no completa la ficha sin sujeto, alcance, herramienta y frescura. «Todo está firmado» tampoco sirve sin identidad esperada y política. El objetivo no es acumular archivos de cumplimiento: es poder rechazar un artefacto incorrecto y explicar por qué se aceptó uno correcto.
Transferencia al capítulo 61
Hashes, firmas y digests aparecen aquí como mecanismos dentro de una cadena de confianza. El capítulo 61 abrirá la Parte VI separando lo que la criptografía puede garantizar de lo que depende de identidades, endpoints, políticas, implementación y operación.
Síntesis
Una cadena de suministro segura conserva identidades distintas para fuente, paquete, distribución, artefacto y despliegue. El manifiesto expresa intención; el resolvedor elige; el lockfile registra una resolución; el digest fija bytes. Ninguno sustituye a los demás.
Una firma autentica dentro de un sistema de confianza. Un SBOM inventaría dentro de un alcance. La procedencia afirma cómo se produjo un sujeto. Una build reproducible permite comparar una reconstrucción independiente. Ninguna de esas evidencias, aislada, demuestra que el software sea seguro.
El control decisivo es un gate: recibe un digest, verifica que todas las evidencias se refieren a él, evalúa identidad, proceso, fuente, inventario y riesgo contra una política explícita, y despliega el mismo digest. Esa continuidad convierte metadata dispersa en una decisión defendible y hace posible responder a un compromiso sin adivinar.
Fuentes primarias y documentación técnica
- NIST, SP 800-218 Secure Software Development Framework 1.1, prácticas PW.4 y PS.3; CSRC, 2022.
- SLSA, Specification 1.2 — Provenance, Build Track Basics and Requirements; slsa.dev, consultada 2026-10-06.
- in-toto, Attestation Framework 1.2 y Statement v1; especificación, consultada 2026-10-06.
- SPDX, Specification 3.0.1 — Software; SPDX, consultada 2026-10-06.
- OWASP CycloneDX, Specification 1.7; CycloneDX, consultada 2026-10-06.
- Sigstore, Cosign signing and verification documentation; Sigstore, consultada 2026-10-06.
- Reproducible Builds, Definitions; reproducible-builds.org, consultada 2026-10-06.
- The Update Framework, Specification 1.0.33; TUF, consultada 2026-10-06.
- npm, package-lock.json y npm ci; documentación, consultada 2026-10-06.


