La trampa del sello Verified: firmas malleables amenazan la unicidad del hash en commits de Git

Autor: Publicada 5 min de lectura 128 lecturas

Las imágenes de este artículo han sido generadas con inteligencia artificial. Cómo publicamos

Un nuevo trabajo de investigación de Jacob Ginesin (PhD en Carnegie Mellon y auditor criptográfico en Cure53) desmonta una suposición extendida: que una confirmación (commit) firmada en Git es, por sí misma, un nombre único e inmutable para su contenido. La técnica no rompe SHA-1 ni SHA-256 ni altera el código; aprovecha la malleabilidad de las firmas —formas distintas y válidas de representar la misma firma— para reescribir los bytes de la firma que se incluyen en el objeto commit, cambiando así su hash sin tocar archivos, autor ni fecha. Ginesin documenta tres vectores concretos (ECDSA, RSA/EdDSA con campos OpenPGP no autenticados y S/MIME con codificaciones DER no canónicas) y acompaña su estudio con herramientas de prueba y repositorios demo que muestran cómo GitHub sigue estampando el sello "Verified" tras esas mutaciones.

La raíz del problema no es Git ni los humanos que firman, sino cómo las forjas consumen y confían en la firma: GitHub y otros servicios no normalizan las firmas antes de verificarlas y asocian el sello Verified al hash exacto del objeto recibido. Eso permite escenarios prácticos de explotación: bloquear un commit por su hash deja un hueco —un atacante puede volver a empujar la misma confirmación con firmas re-encodificadas bajo un hash distinto y, aun así, verla marcada como verificada—; sistemas de deduplicación, listas de bloqueo y bitácoras de procedencia que usan únicamente el hash heredarán la misma fragilidad; un espejo comprometido puede devolver confirmaciones válidamente firmadas cuya representación en bytes (y por tanto su hash) difiere de la versión en el forja canónica.

La trampa del sello Verified: firmas malleables amenazan la unicidad del hash en commits de Git
Imagen generada con IA.

Es importante subrayar lo que esto no es: no es una puerta para cambiar el contenido sin que la firma lo detecte. El contenido fílmico de blobs y árboles permanece idéntico, y pinnear un hash completo para obtener código sigue garantizando que recibirás exactamente aquello cuyo hash corresponde o fallará la descarga. La cuestión es semántica y operacional: el sello "Verified" no garantiza que el hash sea un nombre único e inmutable del objeto firmado, y muchas herramientas confían en esa garantía equivocada.

La lección práctica recuerda a un precedente bien conocido en criptografía aplicada: Bitcoin tropezó con una simetría de ECDSA que permitía cambiar el valor s por n − s y modificar el ID de transacción sin la clave privada; la solución fue imponer una forma canónica ("low-S") y, en un cambio arquitectónico, separar firmas de la identificación con SegWit. La recomendación equivalente para forjas es obvia y técnica: canonizar la representación de las firmas antes de verificar y antes de registrar un sello de confianza. En la práctica eso significa aceptar únicamente formas canónicas (por ejemplo low-S para ECDSA), eliminar o normalizar campos no autenticados de OpenPGP y validar/normalizar codificaciones DER en S/MIME.

¿Qué debe hacer cada actor? Para las forjas (GitHub, GitLab, etc.) la acción es clara y urgente: normalizar las firmas antes de marcarlas como verificadas, almacenar y volver a comprobar la forma canonizada y invalidar sellos si la firma o la clave dejan de ser canónicas o son revocadas. Para las herramientas que bloquean por hash, deduplican o computan trazabilidad, la recomendación es no fiarse del hash bruto de un objeto firmado entrante: verificar la firma, canonizarla y luego computar el identificador que usarán para bloqueo o registro, o alternativamente basar la deduplicación en huellas de contenido (árbol/blobs) en lugar del hash del objeto commit completo.

Para desarrolladores y consumidores de paquetes o Actions la buena noticia es que las prácticas recomendadas no cambian de raíz: seguir pinneando a commits completos es correcto, y anclar además checksums independientes de los artefactos o usar sistemas que verifican contenido (por ejemplo derivaciones de salida fija en Nix) añade un respaldo que evita clases enteras de problemas. No obstante, hay un ajuste en la vigilancia: no se debe usar el sello "Verified" como único criterio de seguridad para aceptar o bloquear código; ese sello demuestra quién firmó, no que el hash sea una identidad única e insobornable.

La trampa del sello Verified: firmas malleables amenazan la unicidad del hash en commits de Git
Imagen generada con IA.

El trabajo de Ginesin fue reportado a proyectos relevantes (Git, GNU y forjas) y, al menos en el momento de su publicación, aún esperaba un parche difundido. La comunidad dispone de arreglos conceptuales maduros: canonicalizar firmas es una práctica conocida y bien entendida. El primer punto de atención obvio es S/MIME, donde la herramienta pública reproduce casos que git locales estrictos rechazan pero que GitHub acepta como "Verified".

En resumen, estamos ante un problema de confianza operacional, no de integridad de contenido: los forjes deben corregir su pipeline de verificación para que el badge "Verified" signifique realmente lo que los usuarios esperan. Mientras tanto, los responsables de infraestrucutra de seguridad y suministros deben actualizar su lógica de bloqueo y deduplicación para validar y canonizar firmas antes de confiar en el hash, y los desarrolladores deben seguir anclando dependencias con hashes completos y, cuando sea posible, con checksums adicionales y mecanismos de verificación de artefactos reproducibles.

Para leer el trabajo y las pruebas publicadas por Ginesin se puede consultar su listado en arXiv y reproducir los demos; la búsqueda por autor ofrece el documento y materiales asociados en abierto: arXiv – búsqueda por Jacob Ginesin. Para entender cómo GitHub presenta y documenta la verificación de firmas en commits, su página oficial de documentación es un punto de referencia útil: GitHub Docs – About commit signature verification. Para comprobar localmente firmas de commits y ver cómo git maneja la verificación, la documentación de git sobre git-verify-commit resulta práctica: git-verify-commit.

Cobertura

Relacionadas

Mas noticias del mismo tema.