O segredo que a máscara deixou passar: lendo um vazamento de CI em base64 duplo

Forense Digital & Resposta a Incidentes Nível 2/4 ~3 min 14 de novembro de 2026

O desafio

Uma action de CI hackeada imprimiu isto no log. Remova o base64 que escapou do mascaramento. Recupere o token de publicação npm vazado.

O que você vai aprender

  • Explicar como o comprometimento do tj-actions/changed-files vazou secrets de CI
  • Reconhecer uma saída decodificada que ainda é base64
  • Explicar por que uma segunda camada de codificação derrota o mascaramento de logs do GitHub
  • Distinguir um token de job de curta duração de um token de publicação de longa duração

Habilidades testadas

Reconhecimento de codificaçõesResposta a incidentes de CI/CDTriagem de secrets

Pré-requisitos

  • O que é base64
  • O que um pipeline de CI faz

Como funciona

O GitHub Actions esconde secrets nos logs dos jobs: antes de uma linha ser gravada, o runner troca cada valor de secret registrado por ***. Ele também mascara as formas base64 desse valor, nos três deslocamentos de byte, porque echo $TOKEN | base64 é o truque mais velho do mundo.

Em março de 2025, um atacante redirecionou todas as tags do tj-actions/changed-files, usado por cerca de 23.000 repositórios, para um commit malicioso. O código novo lia a memória do processo do runner, filtrava com grep cada entrada "name":{"value":"...","isSecret":true} e as imprimia com base64 -w 0 | base64 -w 0. A segunda camada muda cada caractere, então nada na linha bate com um padrão mascarado. Em repositórios públicos, qualquer pessoa podia abrir a execução e ler os secrets. Um log do repositório fictício deste hack era assim:

##[group]Run ridgeway-actions/changed-paths@v4
with:
  separator: ,
  files: src/**
env:
  NPM_TOKEN: ***
##[endgroup]
SWtOUFJFVkRUMVpmVkU5TFJVNGlPbnNpZG1Gc2RX...

O bloco env: mostra a máscara funcionando sobre o valor em texto puro. A última linha é o mesmo secret, embrulhado duas vezes, e a máscara nunca o viu.

Erros comuns

  • Parar depois de uma decodificação. O primeiro resultado ainda tem só letras, dígitos, +, / e =: isso é base64 de novo. Decodifique até aparecer texto legível.
  • Responder com o token ghs_. Ele aparece duas vezes (github_token e system.github.token) porque é o GITHUB_TOKEN do próprio job. O GitHub o gera por job e ele expira quando o job termina. O objetivo é o token de publicação do npm, que continua funcionando depois da execução.
  • Responder com o valor do Codecov. O UUID pertence ao CODECOV_TOKEN, um token de upload, não o do npm.
  • Aplicar base64 uma terceira vez. JSON não é base64, então a etapa falha: essa falha indica que você já chegou ao texto puro.

Como se proteger

  • Fixe actions de terceiros em um SHA de commit completo de 40 caracteres, não em uma tag: tags podem ser movidas, que é exatamente o que aconteceu com o tj-actions.
  • Publique no npm com trusted publishing (OIDC), para que nenhum token npm de longa duração fique nos seus secrets.
  • Entregue um secret só ao job ou ao environment que precisa dele: um job que lista arquivos alterados não tem motivo para ver o NPM_TOKEN.
  • Monitore o egress do runner (por exemplo com o StepSecurity Harden-Runner, que detectou o download do payload do tj-actions).
  • Depois de um incidente, troque todos os secrets que as execuções afetadas puderam ler e apague os logs públicos.

Solução completa

Membros Pro e Max desbloqueiam o passo a passo completo.

Assinar Pro

Estatísticas da comunidade

185 resoluções
91% taxa de sucesso
M2F14M3 Primeiro sangue

Hacks de hoje relacionados

38.000+ Hackers Labs reais Grátis
Comece Grátis ou resolva o hack de hoje, sem conta