Ver código-fonte, copiar a chave, controlar tudo
Um investigador abriu o código-fonte da página do ClickUp, encontrou uma chave de API fixa no JavaScript e usou-a para obter 959 endereços de email e 3.165 feature flags internas num único pedido. A chave não tinha âmbito, não tinha limite de taxa e não tinha data de validade.
Um investigador de segurança foi a clickup.com. Abriu o código-fonte da página. Encontrou uma chave de API fixa no JavaScript. Copiou-a. Enviou um pedido GET.
Recebeu 959 endereços de email e 3.165 feature flags internas. Funcionários da Home Depot. Fortinet. Autodesk. Tenable. Rakuten. Mayo Clinic.
Uma string. Um pedido. Tudo.
Como isto acontece
Alguém precisava que o frontend chamasse uma API. A API exigia autenticação. Então colocaram a chave no JavaScript. Envia-se, passa-se ao seguinte, próximo sprint.
Isto não é um ataque sofisticado. Não há exploit, não há zero-day, não há engenharia social. É view-source: e curl. Um browser e um terminal. Daquilo que um estagiário curioso faz no primeiro dia.
A chave não tinha âmbito — podia aceder a tudo o que a API expunha. Não tinha limite de taxa — um pedido devolveu tudo. Não tinha data de validade — a chave funcionava até alguém reparar. Não havia segundo fator — possuir a string era o único portão.
A questão do dinheiro
Fala-se em exposição de dados. Vamos falar do valor destes dados.
959 endereços de email corporativos de empresas do Fortune 500. Isso é uma lista-alvo de spear-phishing pela qual os atores de ameaça pagam. Nomes, funções e o facto de estas empresas usarem o ClickUp — é o contexto de engenharia social que faz o phishing funcionar.
3.165 feature flags internas. Isso é um roadmap. Diz aos concorrentes o que o ClickUp está a construir, o que está a testar, o que está por trás de um portão. Diz aos atacantes que funcionalidades estão meio-feitas e provavelmente vulneráveis.
Isto não é um incidente de privacidade. É uma fuga de inteligência de negócio.
Porque continua a acontecer
Este é o quarto incidente de credenciais em código-fonte sobre o qual escrevemos este mês. O CLI da Bitwarden teve credenciais colhidas porque estavam em ficheiros de texto simples. As variáveis de ambiente da Vercel eram desencriptáveis porque a opção "sensitive" não era a predefinida. Um programador perdeu 634 palavras-passe do Chrome porque a chave de desencriptação estava no mesmo disco.
O padrão é sempre o mesmo: uma credencial existe como string — num ficheiro, numa variável, no código-fonte da página — e algo lê-a. O algo muda. O padrão não.
Chaves de API em JavaScript são a versão mais flagrante porque não é necessário qualquer ataque. A chave está publicada. É servida a todos os visitantes. O browser descarrega-a, apresenta-a e mostra-a a quem fizer clique direito.
O que deveria ter sido diferente
O pedido à API nunca deveria ter sido autenticado com uma chave estática do lado do cliente. As opções:
- Proxy no backend. O frontend chama o seu próprio backend, que guarda a chave do lado do servidor e faz proxy do pedido à API. A chave nunca chega ao browser.
- Tokens com âmbito de sessão. O frontend recebe, após autenticação, um token de vida curta e âmbito restrito. Expira. Só pode fazer o que o utilizador autenticado tem permissão para fazer. Não é uma chave-mestra.
- Nenhuma chave. Se os dados são públicos, sirva-os sem autenticação. Se não são públicos, não os sirva a JavaScript não autenticado.
Fixar uma chave de API em código do lado do cliente é colocar a chave de casa debaixo do tapete e publicar a morada.
O problema do ciclo de vida das credenciais
Esta chave do ClickUp foi provavelmente criada uma vez, colada num ficheiro JavaScript, submetida num repositório, implantada em produção e nunca mais pensada. Ninguém a rotacionou. Ninguém lhe definiu âmbito. Ninguém lhe definiu data de validade. Ninguém monitorizou o que ela acedia.
Esse é o ciclo de vida da maioria das chaves de API na maioria das organizações. Criadas com pressa, coladas onde são necessárias, esquecidas. Acumulam-se por bases de código, ficheiros de configuração, pipelines de CI/CD e, aparentemente, código-fonte de páginas — cada uma uma porta que nunca tranca.
A questão não é se a sua organização tem uma chave destas. A questão é quantas tem e se saberia se alguém copiasse uma hoje.