Snapshot authentication bypass in grafana
Corrija agora. Ela está sob exploração confirmada pelo CISA e tem exploit funcional público.
Apply updates per vendor instructions.
Resumo
Falha no roteador HTTP (macaron) do Grafana permite que requisições para os caminhos literais /api/snapshots/:key, /dashboard/snapshot/:key e /api/snapshots-delete/:deleteKey — com os dois-pontos e o nome do parâmetro digitados ao pé da letra, não substituídos por um valor real — sejam tratadas como rotas estáticas, contornando a extração normal do parâmetro de chave. O resultado é acesso não autenticado ao snapshot de menor chave no banco e, combinado com exclusão, a possibilidade de varrer e destruir todos os snapshots armazenados na instância. O CVSS 9.8 é justificado pela ausência de autenticação e pelo impacto total em C/I/A dos dados de snapshot, mas o raio de ação está limitado à feature de snapshots — não afeta dashboards, datasources ou credenciais diretamente.
Detalhamento técnico
O bug está no router interno do Grafana, baseado no framework macaron (pkg/macaron/router.go). O router tenta primeiro um 'fast match' para rotas estáticas antes de cair no matcher de rotas parametrizadas. Antes da correção, esse fast match não verificava se o path da requisição continha caracteres de parâmetro (':' ou '*'); então uma requisição literal para /api/snapshots/:key — com a string ':key' de fato na URL, não substituída por um valor — batia certo com a definição de rota registrada e era despachada como se fosse uma chamada válida ao handler, só que com o parâmetro de chave vazio.
Nos handlers de pkg/api/dashboard_snapshot.go (GetDashboardSnapshot, DeleteDashboardSnapshotByDeleteKey, DeleteDashboardSnapshot), o valor de c.Params(":key") ou c.Params(":deleteKey") saía vazio nesse cenário, e a query subsequente (GetDashboardSnapshotQuery com Key ou DeleteKey vazio) era executada sem validação, retornando o snapshot com a menor chave primária no banco em vez de um erro. A correção adiciona uma checagem explícita de len(key) == 0 nos três handlers, retornando 404, e ajusta o router do macaron para não usar o fast-match estático quando o path contém ':' ou '*'.
O atacante não controla qual snapshot é retornado — só sempre o de menor ID/chave primária. Isso não é um IDOR clássico de chave arbitrária; é um bypass que expõe sempre o snapshot mais antigo (ou o que sobrar depois de exclusões), o que é suficiente para enumeração sequencial: ver, deletar, ver o próximo que passou a ser o de menor chave, repetir.
Como é explorada
Para visualização, não é necessária autenticação nem configuração especial: basta uma requisição GET para o caminho literal /dashboard/snapshot/:key ou /api/snapshots/:key. Para exclusão sem autenticação, é necessário que o servidor tenha snapshot.public_mode = true no grafana.ini (o padrão é false); nesse caso a requisição para /api/snapshots-delete/:deleteKey remove o snapshot de menor chave sem login. Se o atacante já tiver qualquer credencial válida na instância (qualquer papel, sem exigência de admin), a exclusão funciona independentemente do public_mode, via /api/snapshots/:key ou /api/snapshots-delete/:deleteKey.
O valor prático do bug está na combinação: alternar entre visualizar e deletar o snapshot de menor chave permite percorrer, um a um, todo o conjunto de snapshots da instância — vazando o conteúdo de dashboards compartilhados via snapshot (que podem incluir dados de painéis, valores de métricas e, em alguns casos, texto embutido) e, ao final do processo, apagando permanentemente todos eles. Não há necessidade de adivinhar chaves ou tokens: o comportamento é determinístico e sequencial.
A CISA incluiu esta CVE no catálogo KEV, confirmando exploração ativa observada. O próprio advisory do fornecedor registra que a instância pública do Grafana Cloud foi auditada e não encontrou evidência de exploração antes do patch, mas isso não se estende a instâncias self-hosted, que são o alvo relevante do KEV.
Versões
Como se proteger
Atualizar para Grafana 8.1.6 (branch 8.x) ou 7.5.11 (branch 7.5.x). O advisory recomenda migrar direto de 8.1.4 para 8.1.6, já que a 8.1.5 trouxe apenas uma correção não relacionada em gráficos de barra. Não há indicação de backport para ramos anteriores ao 7.5 — instâncias em versões mais antigas precisam subir de major/minor para receber a correção.
Se a atualização não for viável de imediato, o paliativo divulgado pelo próprio fornecedor é bloquear via proxy reverso (ou equivalente) o acesso aos quatro caminhos literais afetados: /api/snapshots/:key, /api/snapshots-delete/:deleteKey, /dashboard/snapshot/:key e /api/snapshots/:key (repetido no texto original do advisory). Segundo o fornecedor, esses caminhos literais não têm função normal e podem ser bloqueados sem efeito colateral — a exploração depende exatamente de acessar a string literal com os dois-pontos, não de uma URL com parâmetro real substituído, então bloquear esse padrão exato não impede o uso legítimo da feature de snapshot.
Desativar o snapshot.public_mode (mantendo o padrão false) reduz a superfície de exclusão não autenticada, mas não protege contra visualização não autenticada nem contra exclusão por um usuário autenticado qualquer — portanto não substitui o patch ou o bloqueio de caminho.
Como detectar
O próprio advisory do fornecedor detalha como auditar: em logs de proxy reverso/load balancer, procurar requisições para /dashboard/snapshot/:key, /api/snapshots/:key ou /api/snapshots-delete/:deleteKey (com os dois-pontos literais na URL) que retornaram HTTP 200. Em Grafana Enterprise com router_logging = true habilitado (feature de audit log), buscar por requestUri contendo /api/snapshots-delete/ ou /api/snapshots/:key, ou eventos do tipo 'snapshot' combinados com action 'delete'. Instâncias sem esse logging de auditoria habilitado, ou sem retenção de logs de acesso do proxy anteriores ao patch, não têm sinal confiável retroativo de exploração — o Grafana Cloud só conseguiu confirmar ausência de exploração porque tinha esses logs disponíveis.