Voltar para o blog
BunSegurançaTLS

eMudhra sai do SSL/TLS: o que muda no seu app Bun

23 de outubro de 2026·6 min de leitura·Diego Horvatti

A eMudhra anunciou que vai sair do mercado global de certificados SSL/TLS. Se algum domínio seu usa certificado emitido por ela, uma hora ele vai expirar e não vai ter renovação. Este post é pra quem roda app Bun em produção e quer saber se é afetado, como descobrir isso e como migrar sem susto.

Já falei aqui da CA da eMudhra comprometida. Agora é a sequência natural da história: a empresa decidiu sair do negócio. O comunicado oficial está no site da eMudhra.

O que a eMudhra anunciou

A eMudhra é uma autoridade certificadora indiana, conhecida pela marca emSign. Ela vende certificados digitais de vários tipos, e o SSL/TLS público é só uma parte do negócio. É a parte que importa pra gente: o certificado que faz o cadeado aparecer no navegador e que o seu fetch valida quando chama uma API.

A notícia, resumida: a empresa vai parar de oferecer certificados SSL/TLS públicos no mercado global. Quem é cliente vai ter que migrar pra outra CA.

Na prática, sair desse mercado quer dizer três coisas:

  • Nada de certificado novo.
  • Nada de renovação.
  • Os certificados atuais seguem válidos até o fim do prazo, a não ser que algo force uma revogação antes.

O último item é o que mais pesa. Depois de um incidente de segurança, os root programs dos navegadores (Chrome, Mozilla, Apple, Microsoft) têm pouca paciência. Se algum deles deixar de confiar na raiz da CA, o certificado continua "válido" no papel e o navegador recusa mesmo assim.

Por que isso importa mesmo se você nunca comprou nada dela

Você pode estar pensando: "nunca comprei certificado da eMudhra, então não é comigo". Talvez não seja. Mas tem dois cenários em que é com você sim.

O primeiro é o certificado que não foi você quem comprou. Pode ter sido o cliente, o time de infra de três anos atrás ou um revendedor. Muita empresa compra certificado num pacote de "segurança" e ninguém olha a CA que está por trás.

O segundo é a API de terceiro que o seu backend chama. Se um gateway de pagamento, um órgão público ou um parceiro usa certificado emSign e esse certificado para de ser aceito, quem quebra é o seu fetch. E o erro chega como UNABLE_TO_VERIFY_LEAF_SIGNATURE às três da manhã, sem pista nenhuma de que o motivo é uma CA saindo do mercado.

Certificado é a única dependência do seu projeto que tem data marcada pra quebrar.

Como o Bun decide em quem confiar

Esse detalhe pega muita gente de surpresa. Por padrão, o Bun não lê a lista de CAs do sistema operacional. Ele vem com um bundle próprio de certificados raiz, baseado na lista da Mozilla, igual ao Node.

Isso traz duas consequências:

  1. Se a Mozilla tirar uma raiz da lista, uma versão futura do Bun deixa de confiar nela. Você só percebe quando atualiza o runtime.
  2. Se a sua empresa instalou uma CA interna no sistema, o Bun ignora por padrão.

Pro segundo caso, existem dois caminhos. Pra adicionar uma CA extra sem mexer no código:

NODE_EXTRA_CA_CERTS=./certs/ca-interna.pem bun run start

Ou, nas versões mais recentes, pedir pro Bun usar a lista do sistema operacional:

bun --use-system-ca run start

E pra um caso específico, você passa a CA direto no fetch:

const res = await fetch("https://api.parceiro.com.br/pedidos", {
  tls: { ca: Bun.file("./certs/parceiro-ca.pem") },
});

Agora a opinião forte: nunca resolva erro de certificado com rejectUnauthorized: false. Esse "conserto" derruba a validação de TLS inteira e deixa o caminho aberto pra man-in-the-middle. Já vi isso em produção, comitado com o comentário // temporário. Era de 2021.

Como descobrir se algum domínio seu usa emSign

Dá pra fazer um inventário rápido. Pro terminal, o openssl já resolve:

echo | openssl s_client -connect api.seusite.com:443 -servername api.seusite.com 2>/dev/null \
  | openssl x509 -noout -issuer -enddate

Se o issuer tiver "emSign" ou "eMudhra", anote o domínio e a data de expiração.

Se forem muitos domínios, um script em Bun dá conta. Ele usa a API node:tls, que o Bun implementa:

import tls from "node:tls";

const hosts = ["seusite.com", "api.seusite.com", "api.parceiro.com.br"];

for (const host of hosts) {
  const socket = tls.connect({ host, port: 443, servername: host }, () => {
    const cert = socket.getPeerCertificate();
    const issuer = `${cert.issuer?.O ?? ""} ${cert.issuer?.CN ?? ""}`;
    const flag = /emsign|emudhra/i.test(issuer) ? "  <-- ATENÇÃO" : "";
    console.log(`${host}: ${issuer} | expira ${cert.valid_to}${flag}`);
    socket.end();
  });
  socket.on("error", (err) => console.log(`${host}: erro ${err.message}`));
}

Coloque na lista os seus domínios e os das APIs externas que o backend chama. A segunda parte é a que todo mundo esquece.

Vale olhar também:

  • Os arquivos .pem versionados no repositório (git grep -l "BEGIN CERTIFICATE").
  • Os secrets do CI e do provedor de hospedagem.
  • Os apps mobile com certificate pinning. Esse é o pior caso: trocar o certificado sem trocar o pin derruba o app de quem não atualizou.

Como migrar sem derrubar produção

Se você achou certificado da eMudhra, a migração em si é simples. O que pede cuidado é a ordem dos passos.

1. Escolha a nova CA. Pra maioria dos projetos, Let's Encrypt via ACME resolve de graça. Se você precisa de certificado OV/EV por contrato ou exigência de cliente, aí vai pra uma CA comercial.

2. Confira o registro CAA no DNS. Se o domínio tem registro CAA autorizando só a eMudhra, a nova CA vai se recusar a emitir. Isso trava muita migração:

dig CAA seusite.com +short

Se aparecer só 0 issue "emsign.com", adicione a nova CA antes de pedir o certificado.

3. Emita e instale o novo certificado antes de remover o antigo. No Bun.serve, a troca é direta:

Bun.serve({
  port: 443,
  tls: {
    cert: Bun.file("/etc/ssl/novo/fullchain.pem"),
    key: Bun.file("/etc/ssl/novo/privkey.pem"),
  },
  fetch: (req) => new Response("ok"),
});

Use o fullchain, não só o certificado folha. Sem os intermediários, o navegador às vezes funciona porque completa a cadeia sozinho, mas o cliente HTTP do seu parceiro falha. Clássico "na minha máquina funciona".

4. Se tem pinning, publique o novo pin antes. Lance uma versão do app que aceita os dois pins, o antigo e o novo, espere a base de usuários atualizar e só então troque o certificado.

5. Automatize a renovação. E isso vale independente da eMudhra.

O problema de verdade é renovar na mão

A eMudhra é só o gatilho. O CA/Browser Forum aprovou a redução gradual da validade dos certificados públicos: 200 dias a partir de março de 2026, 100 dias em 2027 e 47 dias em 2029. Quem ainda renova certificado na mão, com lembrete no calendário, vai sofrer bem antes de 2029.

Então use a saída da eMudhra como desculpa pra fazer o que já devia estar feito:

  • Certificado emitido e renovado por ACME, sem intervenção humana.
  • Um alerta quando faltarem 14 dias pra expirar qualquer certificado, inclusive o das APIs externas. O script lá de cima, rodando num cron diário, já cobre boa parte disso.
  • Nenhuma CA hardcoded em lugar que você não controla.

Se o seu setup já é assim, a notícia de hoje vira uma linha no changelog. Se não é, ela vira um incidente.

Minha opinião

A notícia em si não assusta. CA saindo do mercado acontece, e o ecossistema de TLS foi desenhado pra isso: tem várias CAs, a validade é curta e existe protocolo de automação. O que assusta é a quantidade de times que nem sabem qual CA assina os próprios certificados.

Rode o script, confira o CAA e automatize a renovação. Dá uma tarde de trabalho e evita a madrugada em claro depois. Se quiser ver como eu organizo infra e deploy nos meus projetos, dá uma olhada nos projetos aqui do site.

Resumo para o LinkedIn

A eMudhra vai sair do mercado de SSL/TLS, e muito time nem sabe qual CA assina os próprios certificados.

Se o certificado do seu domínio é emSign, ele vai expirar e não vai ter renovação. Pior ainda se for a API do seu parceiro: aí quem quebra é o seu fetch, às três da manhã.

No Bun, o primeiro passo é um script de 15 linhas que lista o emissor e a validade de cada domínio. Depois é olhar o registro CAA no DNS e trocar para o fullchain da nova CA antes de remover o certificado antigo.

E por favor, nada de rejectUnauthorized: false com comentário "// temporário".

Com a validade caindo para 47 dias até 2029, quem renova certificado na mão vai sofrer de qualquer jeito. Escrevi o passo a passo completo no blog, o link está nos comentários.

#Bun #TLS #DevOps #SegurançaDaInformação #JavaScript