
Análise do CVE-2026-22874: lista de permissões SSRF incompleta no webhook/migração do Gitea (transição IPv6 e metadados de nuvem). Corrigido no Gitea 1.26.3.
Análise técnica e referências para CVE-2026-22874 (GHSA-2r5c-gw76-rh3w): uma lista de permissões SSRF incompleta na entrega de webhooks e na migração de repositórios do Gitea, corrigida no Gitea 1.26.3.
Reportei essa classe de SSRF de forma independente aos mantenedores do Gitea e fui creditado como contribuidor (other) no advisory publicado; o relator principal do advisory é J. Leitschuh. Este repositório é uma análise defensiva e educacional do advisory público — o problema está corrigido.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N)<= 1.26.2 — Corrigido: 1.26.3A lista de permissões SSRF padrão do Gitea (MatchBuiltinExternal, usada tanto na entrega de webhooks quanto nas migrações de repositórios) dependia de , da biblioteca padrão do Go, que reconhece apenas RFC 1918 (, , ) e RFC 4193 (). Diversas faixas de endereços comumente usadas para serviços de metadados de nuvem, redes internas e mecanismos de transição IPv6 não são "privadas" segundo essa definição e, portanto, passavam pelo filtro "externo", permitindo que um usuário autenticado fizesse o servidor emitir requisições HTTP para esses destinos.
net.IP.IsPrivate()10/8172.16/12192.168/16fc00::/7Como a entrega de webhooks registra o status da resposta, os cabeçalhos e até ~1 MiB do corpo e os exibe na interface do histórico de webhooks, o SSRF não é cego: o atacante consegue ler o que o serviço interno visado retorna.
net.IP.IsPrivate()| Faixa | Significado |
|---|---|
100.64.0.0/10 | RFC 6598 NAT de operadora (CGN) |
168.63.129.16/32 | Azure WireServer / endpoint de metadados de instância |
64:ff9b::/96 | RFC 6052 NAT64 (pode incorporar 169.254.169.254, ex.: AWS IMDS) |
2001::/32 | RFC 4380 Teredo |
2002::/16 | RFC 3056 6to4 |
As formas IPv6 com mapeamento IPv4 dos endereços acima são afetadas da mesma forma.
Um usuário autenticado que possa criar ou modificar um webhook (ou iniciar uma migração) pode, portanto, alcançar endpoints de metadados de nuvem — por exemplo, AWS IMDS por meio de um mapeamento NAT64, ou o Azure WireServer em 168.63.129.16 — e serviços acessíveis apenas internamente, e então ler a resposta pela visualização do histórico de webhooks.
A política padrão é MatchBuiltinExternal na verificação HostMatchList do Gitea, que considerava permitido qualquer endereço unicast global não IsPrivate():
case MatchBuiltinExternal:
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
return true
}
net.IP.IsPrivate() não é uma fronteira de segurança para "externo": ela não considera NAT de operadora, endpoints de metadados de nuvem ou faixas de transição IPv6 que podem ser roteadas para destinos internos ou de metadados.
Corrigido no Gitea 1.26.3 com a extensão do filtro embutido para bloquear as faixas adicionais acima. Os operadores devem atualizar para a versão 1.26.3 ou posterior. Como defesa em profundidade: