Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
  • Home
  • Programação
  • Git 3.0 Vai Forçar SHA-256: A Mudança que Pode Quebrar Milhões de Repos
Programação

Git 3.0 Vai Forçar SHA-256: A Mudança que Pode Quebrar Milhões de Repos

Email : 10

Imagina chegar na segunda-feira, rodar um git init e descobrir que nenhum dos seus scripts de CI/CD funciona mais. Seus submodules estão quebrados, seus hooks falhando, e aquele pipeline que você levou três sprints pra montar virou pó. Parece exagero? Scott Chacon, cofundador do GitButler e autor do livro Pro Git, acha que é exatamente isso que vai acontecer quando o Git 3.0 trocar o hash padrão de SHA-1 para SHA-256.

A discussão explodiu no Hacker News com mais de 385 comentários e opiniões divididas. De um lado, os que defendem a migração por questões de segurança. Do outro, quem argumenta que a cura pode ser pior que a doença. Eu fui fuçar os dois lados, os detalhes técnicos e as alternativas propostas.

O que muda no Git 3.0

O Git 2.56 já chegou como release candidate em setembro de 2026, e com ele veio a confirmação: repositórios novos criados com Git 3.0 vão usar SHA-256 por padrão. Junto com isso, duas outras mudanças importantes:

  • O formato de referências muda para reftable (adeus arquivos soltos em .git/refs/)
  • A branch padrão passa a ser main em vez de master

Parece simples na superfície. Repositórios existentes continuam funcionando com SHA-1. A mudança só afeta repos novos. Mas aí você para pra pensar cinco minutos e percebe o tamanho do estrago potencial.

AspectoSHA-1 (atual)SHA-256 (Git 3.0)
Tamanho do hash40 caracteres hex64 caracteres hex
SegurançaColisões demonstradasSem ataques conhecidos
CompatibilidadeUniversalApenas Git 3.0+
Submodules cross-formatN/ANão suportado
Conversão in-placeN/ANão existe

SHA-1 realmente é um problema?

Pra entender por que o Git quer migrar, precisa voltar um pouco no tempo. Em 2017, pesquisadores do Google e do CWI (Centrum Wiskunde & Informatica, na Holanda) publicaram o SHAttered, a primeira colisão prática de SHA-1. Eles criaram dois PDFs diferentes com o mesmo hash SHA-1. Custou cerca de 110 mil dólares em processamento na nuvem.

Em 2020, o ataque “SHA-1 is a Shambles” reduziu o custo pra algo em torno de 45 mil dólares. O preço continua caindo com hardware mais barato e GPUs mais poderosas.

O Git usa SHA-1 pra tudo: identificar blobs (arquivos), trees (diretórios), commits e tags. Cada objeto no repositório é endereçado pelo seu hash SHA-1. Se alguém conseguir gerar um objeto diferente com o mesmo hash, teoricamente poderia substituir código sem ninguém perceber.

Mas aqui entra um detalhe que muita gente ignora.

Colisão vs. segunda pré-imagem

Existem dois tipos de ataque contra funções hash:

Ataque de colisão: você controla os dois inputs e precisa encontrar dois que gerem o mesmo hash. Foi isso que o SHAttered demonstrou.

Ataque de segunda pré-imagem: você tem um arquivo existente (que não controla) e precisa criar outro arquivo diferente que gere o mesmo hash. Esse é ordens de magnitude mais difícil.

Para comprometer um repositório Git na prática, um atacante precisaria do segundo tipo. Ele teria que pegar um commit existente e criar outro commit diferente (com backdoor, por exemplo) que gerasse exatamente o mesmo hash SHA-1. Até hoje, ninguém demonstrou um ataque de segunda pré-imagem viável contra SHA-1.

Como Scott Chacon coloca: se você quer comprometer a supply chain de um projeto, existem dezenas de formas mais fáceis. Tomar conta de um pacote no npm, fazer phishing num mantenedor, contribuir código malicioso disfarçado num PR enorme. Nenhuma dessas exige gastar dezenas de milhares de dólares em GPUs pra calcular uma colisão de hash.

A mitigação que já existe

Desde o Git 2.13.0 (2017), o Git usa sha1collisiondetection por padrão. Esse algoritmo, desenvolvido pelos mesmos pesquisadores que criaram o SHAttered, detecta tentativas de colisão durante o cálculo do hash e gera um erro. Na prática, o tipo de colisão demonstrado até agora simplesmente não funciona contra Git moderno.

# O Git já usa sha1dc internamente
# Se detectar padrões de colisão, rejeita o objeto
$ git hash-object arquivo-malicioso.pdf
fatal: SHA1 collision detected for arquivo-malicioso.pdf

O cenário atual é: o ataque conhecido não funciona no Git, e ataques mais sofisticados que poderiam funcionar (segunda pré-imagem) ainda são computacionalmente inviáveis.

O custo real da migração

E aqui mora o problema. Mesmo que SHA-256 seja tecnicamente superior, a migração traz custos que a maioria dos devs ainda não calculou.

Repositórios incompatíveis

Um repositório SHA-1 e um repositório SHA-256 são mundos diferentes. Você não pode fazer push de um para o outro. Não pode fazer fetch entre eles. São formatos incompatíveis.

“Ah, mas só afeta repos novos.” Sim. E aí começa a fragmentação. Você cria um projeto novo em 2027, ele nasce SHA-256. Seu colega clona, funciona. Mas e quando você precisa adicionar como submodule num projeto mais antigo que ainda é SHA-1?

Submodules quebrados

Submodules só funcionam entre repositórios do mesmo formato de hash. Isso não é um bug, é uma limitação arquitetural. Se seu projeto principal é SHA-1 e a biblioteca que você precisa migrou pra SHA-256, você tem um problema sem solução elegante.

Ecossistemas inteiros dependem de submodules. O Yocto Project, por exemplo, é construído em cima de meta-layers como submodules. Android AOSP usa centenas de submodules. Qualquer projeto que misture repos antigos com novos vai bater nesse muro.

# Isso simplesmente não funciona
$ git submodule add https://github.com/lib/nova-lib.git  # SHA-256
fatal: cannot add SHA-256 submodule to SHA-1 repository

# Não existe conversão in-place
# Você precisaria recriar todo o histórico

Todos os hashes mudam

Cada commit, cada blob, cada tree ganha um hash novo. Aquele commit a1b2c3d que você referencia nos seus PRs, na documentação, nos comentários do código? Deixa de existir. Links para commits específicos no GitHub? Quebram.

Commits assinados com GPG? A assinatura é sobre o conteúdo que inclui o hash SHA-1. Num repositório SHA-256, essas assinaturas ficam inválidas.

CI/CD e ferramentas

Todo script que faz parse de hashes Git precisa ser atualizado. Se seu pipeline espera hashes de 40 caracteres e recebe 64, vai quebrar. Regex que valida commits? Falha. Ferramentas de code review que armazenam hashes? Inconsistentes.

# Regex comum pra validar commit hash
# Isso vai falhar com SHA-256
import re
sha1_pattern = r'^[0-9a-f]{40}$'  # 40 chars

# Precisa virar
sha256_pattern = r'^[0-9a-f]{64}$'  # 64 chars

# Ou melhor, aceitar ambos
any_hash = r'^[0-9a-f]{40}([0-9a-f]{24})?$'

O elefante na sala: GitHub

Até onde se sabe, o GitHub ainda não oferece suporte completo a repositórios SHA-256. Quando oferecer, terá que manter dois backends rodando simultaneamente. Segundo o artigo do Chacon, fontes dentro do Google indicaram que o Google pode sobrescrever o padrão internamente pra manter SHA-1, simplesmente porque o custo de migração é alto demais.

A alternativa que ninguém ouviu

Scott Chacon não só criticou a decisão: ele propôs uma alternativa. Criou o projeto tree-sha256, que calcula o hash SHA-256 do conteúdo real de uma tree Git (incluindo submodules), e permite que você assine tags com SSH carregando esse hash.

A ideia é simples: mantenha o SHA-1 como chave de endereçamento (que é o que o Git realmente precisa), mas adicione verificação SHA-256 por cima, como uma camada de integridade independente.

# Instalar a ferramenta
$ cargo install tree-sha256

# Gerar hash SHA-256 da tree atual
$ tree-sha256
sha256:a3f8c7d2e1b4...

# Criar uma tag assinada com o hash SHA-256 embutido
$ tree-sha256 tag --sign v1.0.0

Essa abordagem é inspirada no git-evtag, que existe desde 2015 e foi usado pela comunidade Fedora/rpm-ostree justamente pra esse propósito. A vantagem? Não quebra nada. Repositórios SHA-1 continuam funcionando. Submodules continuam funcionando. CI/CD não precisa mudar. Você só adiciona uma verificação extra pra quem precisa de garantias mais fortes.

AbordagemQuebra compatibilidadeCusto de migraçãoSegurança
SHA-256 padrão (Git 3.0)SimAltoTotal
tree-sha256 (Chacon)NãoBaixoVerificação independente
SHA-1 + sha1dc (atual)NãoZeroSuficiente pra maioria

O que o Rust tem a ver com isso

Outra mudança do Git 3.0 que passou mais despercebida: compilar o Git vai exigir Rust. Partes do código estão sendo reescritas em Rust por questões de segurança de memória.

Faz sentido técnico. C tem décadas de CVEs relacionados a buffer overflow e use-after-free. Rust elimina essas classes de bug por design. Mas adiciona Rust como dependência de compilação, o que impacta distribuições Linux que mantêm builds from source e ambientes embarcados onde cross-compilation já é complicada.

# Compilar Git 3.0 vai precisar de
$ rustc --version  # Rust compiler
$ cargo --version  # Cargo package manager
# Além dos deps tradicionais em C

Na prática, o que fazer?

Se você está se perguntando o que fazer agora, a resposta depende do seu contexto.

Se você mantém projetos open source: não migre proativamente pra SHA-256. Espere o ecossistema se estabilizar. Mantenha seus repos em SHA-1 até que o GitHub, GitLab e Bitbucket tenham suporte maduro e testado.

Se você gerencia infraestrutura Git corporativa: comece a testar. Crie repos SHA-256 em ambiente de homologação. Valide seus pipelines de CI/CD. Identifique scripts que fazem parse de hashes. Faça um inventário de submodules.

Se você é dev e não quer surpresas: ao criar um repo novo com Git 3.0, saiba que ele nasce SHA-256 por padrão. Se precisar de compatibilidade com repos antigos, force SHA-1 na criação:

# Forçar SHA-1 num repo novo (Git 3.0)
$ git init --object-format=sha1

# Ou configure globalmente
$ git config --global init.objectFormat sha1

# Verificar o formato do repo atual
$ git rev-parse --show-object-format
sha1

Se você se preocupa com segurança: use assinatura de commits com SSH ou GPG. A integridade vem da assinatura criptográfica, não do algoritmo de hash do Git. Considere adotar o tree-sha256 pra verificação independente.

# Assinar commits com SSH (mais simples que GPG)
$ git config --global gpg.format ssh
$ git config --global user.signingkey ~/.ssh/id_ed25519.pub
$ git config --global commit.gpgsign true

Quem tem razão?

Os dois lados têm argumentos válidos. SHA-1 já foi quebrado em cenário de colisão, e embora segunda pré-imagem ainda seja inviável hoje, a história mostra que ataques só ficam mais baratos. Eventualmente, SHA-256 vai ser necessário.

O ponto do Chacon é sobre timing e abordagem. Forçar SHA-256 como padrão antes do ecossistema estar pronto cria um período de transição caótico onde metade dos repos é de um tipo e metade de outro. A alternativa dele, de manter SHA-1 pra endereçamento e adicionar SHA-256 como verificação, evita o caos e ainda resolve o problema de segurança.

Eu particularmente acho que a decisão do Git está correta no longo prazo, mas prematura na execução. A falta de conversão in-place, a incompatibilidade de submodules e a dependência do suporte das plataformas (GitHub, GitLab) são problemas reais que não vão desaparecer com um git init.

O que provavelmente vai acontecer: assim como a mudança de master pra main, a migração vai ser lenta, dolorosa e cheia de workarounds. Empresas grandes vão sobrescrever o padrão internamente. Projetos com submodules vão ficar presos no SHA-1 por anos. E eventualmente, daqui a uns 5 anos, todo mundo vai ter migrado e esquecido que era um problema.

Até lá, eu recomendo fortemente dar uma olhada no artigo original do Scott Chacon no blog do GitButler e na proposta do tree-sha256. Independente de qual lado você está, é bom saber o que vem por aí.


Fonte de inspiração: Git 3.0’s upcoming SHA-256 default will be a costly mistake por Scott Chacon

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts