Git 3.0 traerá varios cambios incompatibles, y uno de ellos va a afectar a casi todo el mundo aunque se hable poco de él: los repositorios nuevos usarán SHA-256 en lugar de SHA-1 para identificar commits, árboles y ficheros. Scott Chacon, cofundador de GitHub y GitButler y autor de Pro Git, ha publicado un artículo largo y muy crítico en el que dice que será un cambio carísimo para casi ningún beneficio.
Lo he leído con atención porque, aunque el tono es de rant, los argumentos son serios y hay una propuesta alternativa concreta.
Por qué Git quiere dejar SHA-1
Git es una base de datos direccionada por contenido: cada objeto se guarda con el hash de su contenido como clave. Cada commit incluye el hash del anterior, así que el hash del último commit “resume” toda la historia. Desde 2005 ese hash es SHA-1.
El problema es que SHA-1 se considera roto desde que se publicaron colisiones prácticas: SHAttered en 2017 y SHA-1 is a Shambles en 2020. Con suficientes GPUs se pueden fabricar a propósito dos ficheros distintos con el mismo hash. Git respondió en 2017 con sha1dc, una versión de SHA-1 que detecta ese tipo de colisiones, y desde entonces ha ido preparando la transición a SHA-256, que se puede probar desde hace años:
git init --object-format=sha256 prueba
cd prueba
git rev-parse --show-object-format # sha256
En Git 3.0 eso pasará a ser lo que hace git init por defecto.
El argumento de Chacon: el hash no es la confianza
Chacon empieza separando dos tipos de ataque que solemos mezclar:
| Ataque | Qué hace el atacante | Situación con SHA-1 |
|---|---|---|
| Colisión | Fabrica dos ficheros con el mismo hash, uno inocente y uno malicioso, y luego los cambia | Posible, con mucho dinero en GPUs |
| Segunda preimagen | Fabrica un fichero con el mismo hash que uno ajeno ya existente | Inviable incluso con MD5 |
El ataque peligroso de verdad sería el segundo, y no es factible ni con hashes mucho peores que SHA-1. El de colisión exige que el atacante sea quien introduzca el fichero original en el repositorio y que luego consiga que alguien descargue la versión maliciosa de una fuente que no sea la original.
Y ahí está el centro de su argumento, que ya hacía Linus Torvalds cuando creó Git: la seguridad no está en el SHA-1, sino en de dónde haces el pull. Te fías de un repositorio porque confías en quien lo mantiene y en la autenticación de quien lo aloja, no por la firma de un hash.
Los ataques reales lo confirman. Nadie gasta decenas de miles de euros en GPUs para colar un binario con el mismo hash. Lo que ocurre es que alguien consigue permisos de escritura en un paquete npm que usan millones de proyectos, o se gana la confianza de un mantenedor cansado y acaba heredando el proyecto. Comparado con eso, un ataque de colisión es, según sus palabras, “probablemente la forma más tonta posible” de meter código malicioso en un sistema.
Lo que va a costar
Aquí es donde Chacon tiene más razón, creo yo. El cambio de formato no es un detalle interno:
- Los dos formatos no se mezclan. Un repositorio es SHA-1 o SHA-256, y el servidor tiene que saber cuál es al crearlo. Prepárate para ver mucho
fatal: the receiving end does not support this repository's hash algorithm. - Los submódulos tienen que ser del mismo tipo. Una librería que quiera servir a proyectos de los dos formatos necesitará dos versiones.
- Convertir un repositorio existente lo reescribe entero. Cambian todos los hashes, se rompen todas las firmas y dejan de funcionar todos los enlaces a commits que haya en issues, Slack, correos o documentación.
- Todo el código que asume 40 caracteres para un hash tendrá que revisarse: scripts, CI, herramientas internas, expresiones regulares…
- Las librerías alternativas van por detrás. Como la librería de Git tiene licencia GPL y no está pensada para enlazarse, la mayoría de herramientas usan reimplementaciones propias (libgit2, gitoxide, JGit…), y su soporte de SHA-256 es parcial o nulo.
Cita también una charla de Emily Shaffer sobre cómo se prepara Google, en la que dice que podrían forzar internamente SHA-1 en todos los repositorios nuevos para retrasar el cambio todo lo posible. Si Google se plantea eso, el resto lo vamos a notar.
Su alternativa: firmar un segundo hash
La propuesta es mantener SHA-1 como lo que es en la práctica, una clave para guardar y recuperar contenido, y no usarlo para la confianza. Para los proyectos que sí necesitan verificar el contenido, al firmar un commit o un tag se calcularía un hash independiente (SHA-256, BLAKE3…) de todo el árbol y se añadiría como cabecera del objeto firmado.
flowchart LR
A["Árbol del commit"] --> B["SHA-1 · almacenamiento"]
A --> C["SHA-256 del contenido · verificación"]
B --> D["Tag o commit firmado"]
C --> DLa firma cubriría las dos cosas, y para engañarla habría que encontrar contenido que colisione en ambos algoritmos a la vez. Si algún día cae SHA-256, se añade otro algoritmo sin migrar nada. No es una idea nueva: git-evtag, de Colin Walters, hace algo muy parecido desde 2015 con SHA-512.
Chacon ha medido el coste con una prueba de concepto:
| Repositorio | Tamaño | Tiempo |
|---|---|---|
| Chromium con todos sus submódulos | 35 GB, 2,1 millones de ficheros | 5 s |
| Linux | 1,5 GB | 257 ms |
| Git | — | 17 ms |
Es decir, sólo se paga al firmar, y es poco. Además se podría aplicar hacia atrás, añadiendo tags firmados a versiones antiguas.
Mis matices
Comparto buena parte del diagnóstico, pero hay cosas que conviene tener en cuenta al leerlo:
- Chacon no es neutral. GitButler es justo una de esas herramientas que no usan el binario de Git y que tendrán que soportar los dos formatos. No le quita razón, pero explica parte de la intensidad.
- El ataque de colisión no es tan descartable en algunos contextos. El escenario del colaborador que se gana la confianza durante años y luego cambia un fichero es justo el de xz en 2024. Allí no hizo falta ninguna colisión, es cierto, pero con un tag firmado y un binario de pruebas cambiado sin dejar rastro en la historia habría sido todavía más difícil de detectar.
- La transición lleva años diseñándose en la lista de correo de Git, con un plan que contempla la interoperabilidad entre formatos. Chacon lo reconoce al final: casi todos estos argumentos se han discutido allí antes. Lo que pide es pararse a pensar antes de cambiar el valor por defecto, no que se tire el trabajo.
- NIST marca 2030 como fecha límite para SHA-1 en usos criptográficos, y eso pesa mucho en empresas y administraciones. Su respuesta es razonable: si la firma cubre también un SHA-256, SHA-1 deja de proteger nada y pasa a ser sólo una clave.
Qué haría yo ahora
Cuando salga Git 3.0, no hace falta hacer nada con los repositorios que ya existen: siguen siendo SHA-1 y Git los seguirá manejando. Lo que cambia es git init. Si trabajas con un servidor o con herramientas que todavía no soportan SHA-256, se puede fijar el formato por defecto:
git config --global init.defaultObjectFormat sha1
Y para saber de qué tipo es un repositorio concreto, git rev-parse --show-object-format.
Lo que me llevo
Me quedo con la distinción de fondo, que me parece lo más valioso del artículo: integridad no es lo mismo que confianza. El hash garantiza que nadie ha corrompido el contenido sin querer; la confianza viene de quién mantiene el repositorio, quién tiene acceso y quién firma las versiones. Mezclar las dos cosas lleva a migraciones enormes cada vez que se publica un nuevo ataque teórico, mientras los ataques reales siguen entrando por la cadena de suministro.
No sé si Git 3.0 acabará cambiando el valor por defecto o no, pero el debate merece la pena seguirlo, porque cuando llegue nos va a tocar a todos.




