A chave do DNS mudou, o Deno virou Cloudflare e o npm foi envenenado de novo

Neri Filho

Nenhum item desta semana aparece num diff. A chave que assina a raiz do DNS mudou no domingo, e o seu resolvedor ou seguiu ou não seguiu, sem nada a ver com o seu código. O time que mantém o Deno foi trabalhar na Cloudflare, e o runtime passou a ter prazo. Um pacote do npm foi publicado pelo pipeline legítimo do projeto, com procedência de build válida, e com um verme dentro. O driver JDBC do Postgres descobriu que vinha preenchendo valor curto com bytes de mensagens anteriores da conexão, e o servidor guardava aquilo. A Anthropic trocou a forma de cobrar, não o número: o preço do Haiku agora depende do tamanho do prompt.

A camada que mudou, em todos esses casos, é a que você não versiona. Trust anchor de resolvedor, pipeline de publicação de registro, preenchimento de buffer de driver, tabela de preço de fornecedor, dono do runtime. Nenhuma dessas coisas está no seu package.json, e é justamente por isso que elas chegam sem aviso. A semana passada era sobre etiqueta que fica igual enquanto o conteúdo muda. Esta é um degrau abaixo: o conteúdo mudou num lugar onde você nem tem etiqueta para olhar.

Oito itens. Três desenvolvidos. O primeiro tem prazo de validade curto, então começo por ele.

Destaques

A raiz do DNS trocou de chave no domingo, e a quebra chega com atraso

Em 11 de outubro, às 00:00 UTC, a raiz do DNS passou a assinar o próprio conjunto de chaves só com a KSK-2024, de key tag 38696. A anterior, KSK-2017, de key tag 20326, parou de assinar. É a segunda troca de chave da raiz na história, e a Cloudflare avisou com antecedência em 6 de outubro, com os comandos de verificação. A ICANN publicou orientação em agosto pedindo que operador de resolvedor validador confirmasse a chave nova à mão, em vez de supor que a atualização automática funcionou.

Eu fui conferir antes de escrever, porque convém. Consultei o conjunto DNSKEY da raiz e a assinatura que chega hoje é da chave 38696, com início de validade em 11 de outubro às 00:00 UTC e fim em 1º de novembro. As duas chaves continuam publicadas na zona, o que é normal nessa fase: o que mudou é qual delas assina. Rodei também o teste de sentinela contra o 1.1.1.1, aquele par de consultas root-key-sentinel-is-ta-38696 e root-key-sentinel-not-ta-38696 que o post da Cloudflare ensina. A primeira respondeu com registro válido, a segunda devolveu SERVFAIL, que é exatamente a assinatura de um resolvedor que confia na chave nova. Então a troca aconteceu e o 1.1.1.1 está do lado certo dela.

Agora a parte que importa para esta semana, e o motivo de o item ser o primeiro. A falha não é imediata. A chave velha tem TTL de 48 horas, então resolvedor validador que ficou sem a KSK-2024 continua respondendo enquanto o cache dura e começa a devolver SERVFAIL depois, conforme as entradas expiram. O efeito nesse resolvedor não é "um domínio parou": é validação de DNSSEC falhando para zona assinada, o que na prática derruba TLD inteiro para quem usa aquele resolvedor. Ou seja, a janela em que isso aparece é exatamente agora, entre segunda e meio de semana, e vai aparecer como "a internet caiu" num lugar só, sem mudança nenhuma do lado de quem reclama.

Quem usa resolvedor de provedor grande ou 1.1.1.1 e 8.8.8.8 não tem o que fazer. Quem roda o próprio Unbound, BIND ou Knot, em container de CI, em VPC, em appliance de rede ou naquela VM que ninguém toca desde 2019, tem uma coisa para fazer hoje: olhar o arquivo de trust anchor e confirmar que a 38696 está lá. Em BIND é o bind.keys ou o managed-keys; em Unbound é o root.key do auto-trust-anchor-file. A revogação formal da KSK-2017 fica para 2027, então ainda dá tempo de arrumar sem pressa de relógio, mas não de cache.

O time do Deno foi para a Cloudflare, e o runtime ganhou prazo

Em 9 de outubro a Cloudflare anunciou que o time do Deno está entrando na empresa. O post é assinado por Ryan Dahl e Kenton Varda, e o objetivo declarado é tornar o auto-hospedado um caminho de primeira classe para rodar aplicação no modelo de Workers e Durable Objects. Ryan Dahl e Bert Belder passam a liderar esse esforço. Em termos de código, o plano é fundir o celld, a implementação de Workers e Durable Objects que o time do Deno lançou em agosto (um binário em Rust, com armazenamento de objetos como única dependência externa), com o workerd, o runtime aberto da Cloudflare, cujo suporte a Durable Objects hoje é limitado a uma instância.

Os prazos estão no post do próprio Dahl no blog do Deno, e são três, bem diferentes entre si:

  • o runtime Deno recebe mais um ano de lançamentos mensais com correção de bug e de segurança. Depois disso, o desenvolvimento encerra. O projeto continua aberto, e o post convida quem quiser a seguir com ele;
  • o Deno Deploy opera por mais seis meses e desliga. Cliente pagante que migrar para Workers tem apoio na migração;
  • o JSR continua operando, e a infraestrutura dele passa para a Cloudflare.

Vale separar as três notícias, porque elas pedem reações diferentes. O JSR continuar é o melhor resultado possível: registro de pacote que desliga quebra build de terceiro para sempre, e esse risco saiu da mesa. O Deno Deploy desligando em seis meses é um prazo de migração, com data, e prazo com data é a parte fácil de planejar. O runtime é o item desconfortável, e não pelo ano de correções: um ano de patch de segurança é mais do que muito projeto comercial entrega. É pelo que vem depois.

"Continua aberto" é verdade e não é promessa de nada. Quem roda Deno em produção passa a ter, a partir do fim desse ano, um runtime cuja manutenção depende de aparecer alguém para mantê-lo. Isso não é motivo para reescrever nada em pânico: é motivo para transformar a dependência em decisão datada. Se o seu serviço em Deno usa API compatível com Node, a saída é barata e você tem doze meses de folga para medir isso com calma. Se usa Deno.serve, KV ou permissão granular do runtime a fundo, a conta é outra, e a hora de descobrir qual é das duas é agora, não no mês onze.

Tem uma leitura de mercado aqui que não dá para fingir que não existe, e ela tem consequência técnica. O modelo de Workers acabou de absorver o seu principal concorrente aberto, e os dois runtimes abertos do nicho viraram um. Menos implementações independentes significa menos pressão sobre a especificação e mais peso no desenho de um fornecedor. O contrapeso real, e o post é explícito nele, é o auto-hospedado ficar de fato viável: celld e workerd podem ser rodados hoje, fora da Cloudflare. Se isso virar caminho sério em vez de item de release notes, a troca é razoável. Se não virar, a palavra "aberto" vai carregar menos do que carregava na semana passada.

Pacote envenenado no npm, com procedência de build válida

Em 8 de outubro, à 01:12 UTC, a versão 0.5.144 do pacote tensorlake, o SDK oficial em TypeScript da Tensorlake, foi publicada no npm com o verme Shai-Hulud dentro. A Endor Labs publicou a análise no mesmo dia e a reconstrução é precisa: o primeiro commit malicioso entrou no branch principal do repositório em 7 de outubro, à 01:20 UTC, e cerca de 24 horas depois o pipeline normal de release do projeto, em GitHub Actions, publicou a versão envenenada. A 0.5.143 e as anteriores estão limpas. A 0.5.144 já saiu do npm, junto com os seis pacotes binários tensorlake-native-* da mesma publicação.

O que o payload faz é o repertório conhecido da família, e vale listar porque define o raio do estrago: um hook de preinstall roda lib/setup.mjs durante o npm install, antes de qualquer código seu executar; de lá sai um blob ofuscado de uns 856 KB que busca e executa um segundo estágio; e esse estágio colhe token de npm, token e configuração de GitHub, chave SSH, credencial de AWS, GCP e Azure, configuração de Kubernetes e de Docker, token de Vault e arquivo .env. Em máquina de nuvem, ele consulta o endpoint de metadados da instância para pegar credencial temporária. Com o que colhe, republica a si mesmo em pacotes que a vítima controla, que é o que faz dele verme e não ladrão.

O detalhe que eu quero que você leve desta semana não é nenhum desses. É este: a publicação carregava procedência de build válida. A Endor Labs diz a frase certa, que procedência mostra de onde o build veio, não que a fonte estava limpa. Pare um segundo nisso, porque é a parte que mexe com decisão de arquitetura. Procedência, build reproduzível e publicação sem credencial de longa duração são boas práticas, e elas resolvem uma classe de ataque específica, que é alguém publicar de fora do pipeline. Não resolvem esta, que é alguém mexer na fonte e deixar o pipeline fazer o trabalho direito. Assinatura prova origem. Não prova intenção. Se a sua leitura de "pacote com procedência" era "pacote conferido", esta semana corrigiu isso de graça.

Na prática, para quem instala coisa do npm em CI, duas defesas valem mais que procedência aqui e as duas são chatas de propósito. A primeira é --ignore-scripts, porque o vetor inteiro depende de um hook de preinstall; no CI isso costuma custar pouco, e o que depender de script de instalação você libera por exceção. A segunda é atraso: pinar versão exata e não instalar release publicada nas últimas horas. A 0.5.144 viveu pouco. Quem atualiza no mesmo dia pegou; quem tinha lockfile pinado e um dia de folga não pegou. Se você instalou a 0.5.144 em qualquer lugar, principalmente em runner de CI, trate como vazamento confirmado e rode a rotação toda: npm, GitHub, SSH, nuvem e o que mais estava naquela máquina.

Em nota

  • Next.js 16.4, e uma liberação de segurança marcada para quarta. O 16.4 saiu em 6 de outubro e o recado principal é de modelo, não de recurso: Cache Components passa a ser a recomendação para qualquer app, vira padrão no create-next-app agora e padrão do framework no 17. Vêm também ensureStatic, que faz o build falhar se conteúdo dinâmico entrar numa rota que devia ser estática, as funções navigation() e prefetch() para tirar conteúdo do prefetch, React 19.3, e cache de disco do Turbopack 20% a 25% menor. O resto do anúncio é ferramenta de agente: next upgrade --agent e um experimental.agentUpgrade cuja política padrão é security. Separado disso, e mais urgente, em 8 de outubro a Vercel avisou que vai publicar uma liberação fora de ciclo em 14 de outubro, com três falhas em dependências de terceiro, duas críticas e uma alta, sendo que duas foram adiadas da liberação de setembro por coordenação com o projeto de origem. Não há o que fazer hoje além de pôr quarta na agenda e saber quem aplica.
  • O Haiku 5.5 cobra por tamanho de prompt, e cache conta no limiar. A Anthropic lançou o Claude Haiku 5.5 em 7 de outubro, e o que muda de verdade não é o preço, é o eixo dele. Pela tabela oficial, prompt de até 100 mil tokens custa 0,10 dólar por milhão de entrada e 0,50 de saída; acima de 100 mil, vai para 0,50 e 2,50. Contra 1 e 5 do Haiku 4.5, é 90% mais barato embaixo do limiar e 50% acima. A pegadinha está na definição: o tamanho do prompt conta todos os tokens de entrada da requisição, leitura de cache inclusive. Quem monta agente com prompt de sistema grande e cacheado pode cruzar os 100 mil sem nunca enviar 100 mil tokens novos, e pagar cinco vezes mais por isso sem que a métrica de "tokens novos por tarefa" mostre. A Anthropic também cortou pela metade a leitura de cache do Sonnet 5.5, de 0,20 para 0,10 por milhão, o que fecha a conta do Radar da semana passada: a razão entre entrada cheia e entrada em cache nessa faixa virou vinte.
  • Python 3.15.0 saiu em 9 de outubro, no prazo novo. A data que havia escorregado do início de outubro foi cumprida, e o 3.15.0 está publicado. A capa é a importação tardia explícita da PEP 810, com a palavra-chave suave lazy, válida só em escopo de módulo. Vêm junto frozendict (PEP 814), o tipo sentinel (PEP 661), desempacotamento em compreensão (PEP 798), um pacote de profiling (PEP 799) com o amostrador estatístico Tachyon, e o JIT experimental bastante melhorado. Mas a entrada que tem mais chance de te morder não é nenhuma dessas: é a PEP 686, que torna UTF-8 a codificação padrão. Todo open() sem encoding= no seu código acabou de mudar de comportamento em quem não estava em UTF-8. Se você tem código que lê arquivo em Windows ou em locale latino, é ali que a atualização dói.
  • A CISA detalhou uma campanha chinesa, e nenhuma das falhas é nova. Em 8 de outubro saiu o aviso AA26-281A, sobre atividade ligada à Integrity Technology Group, empresa chinesa que vende ferramenta de ataque e hospeda infraestrutura, com sobreposição ao que o mercado chama de Flax Typhoon. Olhe a lista de CVE explorada: Bash de 2014, ProFTPD e BIND de 2015, Struts de 2016, Pulse Connect Secure de 2019, GitLab e ONLYOFFICE de 2021, Strapi de 2023. Oito falhas, a mais recente com três anos, cinco delas entrando no catálogo de exploração ativa da CISA só agora. Para persistência eles usam cliente de SoftEther VPN renomeado para conhost.exe ou dllhost.exe, que é software legítimo e por isso passa por antivírus. A leitura prática é desconfortável e simples: o alvo não é quem demora a aplicar o patch de ontem, é quem tem um host esquecido de dez anos atrás. Inventário vence zero-day nessa categoria.
  • O driver JDBC do Postgres vinha escrevendo lixo de outras mensagens no seu banco. A versão 42.7.14 saiu em 7 de outubro com duas correções de segurança, as duas moderadas, e a segunda merece atenção maior que a nota 5,3 sugere. Na CVE-2026-107315, quando um valor era mais curto que o tamanho declarado, o driver completava o resto com bytes de mensagens anteriores da mesma conexão, e o servidor podia guardar aquilo. Atinge da 42.7.4 à 42.7.13, e agora o preenchimento é sempre zero. Repare no formato do problema: não é acesso indevido, é dado de uma requisição acabando dentro de uma linha de outra, de forma persistente. Se você usa CHAR de tamanho fixo ou tipo binário de tamanho declarado com esse driver, vale olhar o que está gravado. A outra, a CVE-2026-107314, é o requireAuth não sendo aplicado quando o valor não nomeava nenhum método válido, o que deixava o driver aceitar senha em texto claro pedida por um intermediário. Atinge da 42.7.11 à 42.7.13, e a correção é usar lista positiva, tipo requireAuth=scram-sha-256.

O que eu faria com isso esta semana

  1. Hoje, antes de qualquer outra coisa: confirmar a 38696 em cada resolvedor que é seu. São dez minutos e é a única tarefa da semana com cache correndo contra ela. A lista de lugares para olhar é maior do que parece: resolvedor de VPC, resolvedor dentro de imagem de container usada em CI, appliance de rede, e qualquer VM que faz validação de DNSSEC por conta própria. O teste de sentinela do post da Cloudflare responde isso de fora sem precisar entrar na máquina. Se o resolvedor estiver sem a chave, o sintoma vai chegar como SERVFAIL generalizado nos próximos dias, e esse é o tipo de incidente em que se perde a primeira hora procurando no lugar errado.
  2. Pôr --ignore-scripts no npm ci do CI, e um dia de atraso entre publicação e instalação. As duas medidas custam pouco e cobrem o vetor exato desta semana, que é hook de preinstall em versão recém-publicada. Procedência de build não cobre, e agora você tem um caso concreto para mostrar a quem perguntar por quê. Se instalou tensorlake@0.5.144, a resposta não é remover o pacote, é rotacionar credencial da máquina inteira.
  3. Transformar o Deno em decisão com data, não em preocupação. Doze meses de correção é tempo de sobra para fazer a pergunta certa uma vez: este serviço usa API compatível com Node, ou usa o runtime a fundo? A resposta define se a migração é barata ou se é projeto, e saber qual das duas vale mais que decidir agora para onde ir. Cliente de Deno Deploy tem seis meses, e aí sim o prazo é curto para o tamanho da tarefa.
  4. Procurar encoding e open( no código Python antes de subir para o 3.15. A PEP 686 é a mudança da semana com maior chance de quebrar algo em silêncio, porque não dá erro de importação nem de tipo: dá caractere errado, ou exceção de decodificação em arquivo que lia bem. Quem lê CSV de cliente, arquivo gerado no Windows ou retorno de sistema velho em latin-1 deveria passar o grep antes da atualização, não depois.

Radar é a newsletter semanal deste blog: o que aconteceu na semana em tecnologia, com comentário sobre o que muda para quem constrói e opera software.

Tem um desses rodando — ou pra construir?

Me conte em duas linhas. Respondo em até 24h dizendo se é o tipo de coisa que eu faço bem — e se não for, digo isso também.

Outros textos