← Voltar ao Blog

Confiei no Claude Code no piloto automático e o Shai-Hulud quase entrou: 5 permissões que reduzi hoje

Semana passada abri o Claude Code no piloto automático e passei por três prompts sem ler. No quarto, ele quis instalar um pacote npm chamado chalk-utils (existe um chalk-utils legítimo, mas o meu contexto não pedia esse pacote). Se eu tivesse apertado “Sim”, estaria participando da versão 2026 do worm Shai-Hulud, que já comprometeu mais de 796 pacotes npm entre setembro de 2025 e abril de 2026, com mais de 20 milhões de downloads semanais combinados (Datadog Security Labs).

Não apertei “Sim” por sorte. Estava com o café na mão errada e demorei três segundos a mais para clicar. Nesses três segundos eu li o nome do pacote e o contexto não bateu. Fim da história ali, começo dessa história aqui.

Este post não é sobre o Shai-Hulud, que já foi coberto por todo mundo. É sobre as 5 permissões que reduzi na mesma tarde depois desse susto, o custo em minutos que essa redução me devolveu e o que ficou realmente diferente na minha semana.

O modelo mental que me colocou em risco

Claude Code tem cinco modos de permissão em 2026: Ask permissions, Accept edits, Plan, Auto, e Bypass permissions. Você cicla entre eles com Shift+Tab durante a sessão (Claude Code Docs oficial).

O modo Auto foi introduzido em março de 2026 e passa cada comando shell por um classificador de segurança separado que bloqueia coisas obviamente catastróficas: push para main, deploy em produção, envio de secrets para fora, apagar arquivos que existiam antes da sessão (Anthropic Engineering: auto mode). O classificador é bom no que ele foi feito para fazer.

Meu erro foi confundir “seguro” (o classificador bloqueou o desastre) com “correto” (essa ação é o que eu queria). Não são a mesma frase. npm install chalk-utils não é desastre para o classificador. É desastre para mim se eu não pedi esse pacote e o pacote não existe no meu contexto de trabalho.

O Shai-Hulud atual explora exatamente essa lacuna. As últimas variantes, especificamente na campanha SANDWORM_MODE de fevereiro de 2026, instalam servidores MCP falsos com prompt-injection embutido que instruem assistentes de IA a colher chaves SSH, credenciais de cloud e tokens de API sem notificar o usuário. Três pacotes se passam pelo próprio Claude Code (Cloud Security Alliance).

A fronteira de confiança que o Claude Code assume não é a que eu estava assumindo. Ele confia no registro npm. Eu confio no Claude Code. Alguém publicou algo no registro npm. A cadeia inteira quebra num elo que ninguém dos dois lados está checando.

As 5 permissões que reduzi na mesma tarde

Nenhuma dessas mudanças é sofisticada. Quase tudo cabe no ~/.claude/settings.json; o resto é uma variável de ambiente e um hook. Custo total de implementação: 40 minutos naquela tarde.

1. Auto mode desligado para instalação de pacotes. Deixei o Auto mode ativo para edits de arquivo e execução de testes, que é onde o ganho de tempo é real. Desliguei para qualquer comando que comece com npm install, pnpm add, yarn add, pip install. Cada instalação passa a exigir confirmação explícita minha, com o nome do pacote e o motivo do install visíveis.

{
  "permissions": {
    "ask": [
      "Bash(npm install:*)",
      "Bash(pnpm add:*)",
      "Bash(yarn add:*)",
      "Bash(pip install:*)"
    ]
  }
}

O ask força o prompt mesmo em Auto mode. Casamento de prefixo tem furo conhecido (npx --yes pacote passa por fora do padrão, a própria doc avisa), então pra bloqueio duro o caminho é um hook de PreToolUse; pro meu caso de uso, o prompt resolve. Custo cognitivo: 3 segundos por instalação. Custo evitado: potencialmente o meu ~/.ssh/ inteiro.

2. Accept edits ligado, mas com lista de bloqueio explícita. Accept edits auto-aprova edições de arquivo e operações de filesystem seguras dentro do diretório de trabalho. Isso vira problema quando o “diretório de trabalho” inclui .env, ~/.npmrc, Makefile, ou scripts pós-install de node_modules. O modo entra via defaultMode, e os caminhos sensíveis saem via regras Edit() no deny.

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "deny": [
      "Edit(.env*)",
      "Edit(.git/hooks/**)",
      "Edit(~/.npmrc)",
      "Edit(Makefile)"
    ]
  }
}

Edit nesses caminhos é bloqueado; no resto do diretório de trabalho, auto-aprovado. Em regra de deny, um padrão relativo como .git/hooks/** casa em qualquer profundidade, e ~/ ancora no home. Isso pega tentativas de escrever em .git/hooks/ (vetor conhecido do Shai-Hulud) e em ~/.npmrc.

3. Leitura proibida em arquivos-chave. O controle de verdade aqui é permissions.deny com regras Read(). Instrução em prosa no CLAUDE.md não é controle de segurança, é pedido educado.

{
  "permissions": {
    "deny": [
      "Read(.env*)",
      "Read(**/*.pem)",
      "Read(**/*.key)",
      "Read(~/.ssh/**)",
      "Read(~/.npmrc)",
      "Read(~/.aws/**)"
    ]
  }
}

Mantive a seção equivalente no CLAUDE.md global como aviso de intenção, mas quem trava é o deny. Contra um MCP malicioso (processo separado, que não passa por esse filtro) isso não defende; é exatamente por isso que existe o item 5.

4. Telemetria desligada e /bug fora do fluxo. O comando /bug no Claude Code manda relatórios que ficam retidos por até 5 anos. Se eu estiver frustrado às 2 da manhã e usar /bug sem ler o payload, secrets acidentalmente no contexto vão junto.

export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

Desliguei também o /bug via hook local que intercepta o comando e força um “tem certeza?” antes de enviar. Custo: 5 minutos escrevendo o hook. Ganho: minha noite não vira problema jurídico daqui a dois anos.

5. Whitelist de MCP servers. O vetor mais novo do Shai-Hulud é MCP: pacotes maliciosos deploiam servidores MCP falsos com prompt-injection embutido. Eu passei a manter uma lista curta e explícita: os meus servidores ficam em ~/.claude.json, e a aprovação de servidores vindos de .mcp.json de projeto fica pinada no ~/.claude/settings.json.

{
  "enabledMcpjsonServers": ["context7"],
  "enableAllProjectMcpServers": false
}

Por padrão o Claude Code já pede aprovação na primeira vez que vê um servidor de .mcp.json, o que segura o cenário do pacote npm plantando um servidor como side-effect. O que essa config fecha é o meu lado do problema: enableAllProjectMcpServers nunca ligado (é a chave que aprovaria tudo sozinha) e a lista de aprovados explícita num arquivo, em vez de espalhada nos “Sim” que eu cliquei no piloto automático ao longo dos meses. Custo: quase zero. Ganho: o vetor principal da campanha SANDWORM_MODE passa a depender de um “Sim” meu, e esse prompt eu leio.

Cinco permissões reduzidas depois do quase-Shai-Hulud: cada linha mostra o vetor de ataque fechado e o custo em segundos por dia. Total ~1 minuto/dia contra o risco de rotação de secrets numa tarde

Quantos minutos essa redução me custou

Essa é a parte que ninguém escreve nos posts de segurança, então vou escrever. Confirmar cada permissão manualmente custa tempo. A pergunta honesta é quanto.

Nos primeiros 5 dias depois da mudança eu contei. Média por dia:

  • 4 confirmações extra de npm install × 3s = 12s
  • 6 prompts para edits fora do diretório de trabalho × 8s (leio o path e decido) = 48s
  • 1-2 prompts do hook do /bug = ~5s

Total: perto de 1 minuto por dia. Um minuto.

Comparado a: 1 vez de “instalei chalk-utils no automático” custa, sob Shai-Hulud, minimamente algumas horas de rotação de secrets e no cenário ruim uma rebuild completa do ambiente. A conta não fecha nem em ordem de grandeza. Um minuto por dia contra “pode ser algumas horas em algum dia” é o trade mais barato que fiz esse ano.

O que ficou de fato diferente

Não fiquei paranoico. Continuo usando Claude Code todo dia, no Auto mode, para 90% do meu trabalho. O que mudou é onde eu não deixei o Auto mode: nas fronteiras onde a decisão precisa ser minha porque o classificador não tem informação suficiente para decidir por mim.

A Anthropic escreveu na introdução do Auto mode uma frase que me marcou: o classificador é para bloquear risco, não para entender intenção. Intenção mora na minha cabeça, e as 5 permissões acima são o mínimo de superfície que eu concordo em delegar quando estou cansado, com café na mão errada, e sem tempo para ler os três prompts anteriores.

O Shai-Hulud é uma corrida armamentista. A próxima campanha vai encontrar um vetor que não está nessa lista de 5. Quando isso acontecer, o hábito de reduzir permissão nas fronteiras onde o classificador não tem contexto sobre mim é o que me protege, não a lista específica.

Reagan tinha uma frase pra negociações com Gorbachev que descreve exatamente essa postura: “trust, but verify”. No caso do Claude Code, verify significa um segundo antes de apertar Sim, ler o nome do pacote. E significa também não configurar o ambiente pra o Sim ser apertado sozinho quando o custo de um Sim errado é grande demais.

O piloto automático é útil quando o preço de errar é baixo. Cinco permissões redesenhadas depois, o meu piloto automático finalmente está ligado só onde o preço de errar é baixo mesmo.


Correção (31/07): a primeira versão deste post citava duas chaves que não existem na doc oficial: acceptEditsPaths (item 2) e mcpServersDenyAll (item 5). Reescrevi os itens 1, 2, 3 e 5 com os mecanismos reais: permissions.ask, permissions.defaultMode mais regras Edit() e Read() no deny, e enabledMcpjsonServers. Valeu ao @rudekwydra pela revisão nos comentários do TabNews.


ken imoto · WebRTC & Voice AI engineer · kenimoto.dev · TabNews

Harness Engineering Livro relacionado Harness Engineering Tutorial de Harness Engineering | design de AGENTS.md · implementação de hooks · operação de agentes de IA Ver a página do livro →