NetCatTest

DevSecOps & Supply Chain

Supply chain no npm: OIDC, provenance e o limite das assinaturas

Como avaliar trusted publishing, atestações e o conteúdo de uma release npm sem confundir assinatura válida com ausência de código malicioso.

Por Daniel Felipe 8 min leitura

Um pacote assinado ainda pode conter código malicioso. A assinatura responde a perguntas sobre identidade e integridade. A segurança da release depende também de quem pode alterar o código, de como o build acontece e de qual artefato chega ao registry. Confundir essas camadas deixa uma cadeia de suprimentos aparentemente organizada com pontos de confiança pouco examinados.

Para equipes que publicam no npm, uma revisão útil começa por três perguntas: existe um token permanente capaz de publicar? O workflow autorizado é precisamente identificado? O consumidor consegue relacionar o pacote ao código e ao processo que o produziram? Este guia apresenta uma forma prática de organizar essas decisões.

Digest correto, publicação errada: três verificações diferentes

Um pacote pode ter uma assinatura válida e ainda conter uma alteração maliciosa. Integridade responde se os bytes mudaram depois da assinatura; identidade informa qual chave ou identidade publicou; autorização pergunta se aquela identidade podia produzir aquela release. Em provenance, acrescente a associação entre sujeito, digest, build e origem esperada. Uma branch com nome plausível não é uma política de publicação.

O fragmento abaixo representa uma decisão local sobre uma atestação já verificada criptograficamente. É código didático, não um verificador Sigstore ou uma substituição de npm audit signatures. Usamos um digest sintético para mostrar que o mesmo artefato deve ser recusado quando sua origem muda.

digest = 'ab' * 32
politica = {'repositorio': 'equipe/pacote-lab', 'ref': 'refs/tags/v1.0.0'}
atestacao = {'digest': digest, 'repositorio': 'equipe/pacote-lab',
             'ref': 'refs/tags/v1.0.0'}

def origem_permitida(a):
    return (a['digest'] == digest
            and a['repositorio'] == politica['repositorio']
            and a['ref'] == politica['ref'])

assert origem_permitida(atestacao)
assert not origem_permitida(dict(atestacao, repositorio='fork/pacote-lab'))

As comparações são simples de propósito: deixam visível que um hash não concede autoridade. Na validação real, esses campos precisam vir do material assinado e da cadeia de confiança, não de um JSON ao lado do pacote. Certificado, emissor, identidade de workflow e transparência devem ser verificados pelo mecanismo apropriado.

No inventário, diferencie o digest da distribuição do hash de um arquivo extraído. Um tarball e sua árvore descompactada são objetos distintos. Compare também o que o build pretendia publicar com a lista de arquivos: scripts de instalação, binários, arquivos de configuração e conteúdo gerado podem mudar o comportamento sem alterar o nome do pacote.

Um reteste útil introduz três controles negativos: assinatura inválida, assinatura válida de origem diferente e origem correta com conteúdo inesperado. Cada rejeição demonstra uma fronteira diferente. O relatório fica mais forte quando identifica a política aplicada e o ponto exato da recusa, em vez de apenas registrar que o comando terminou com sucesso. A referência do npm audit ajuda a separar auditoria de vulnerabilidades e verificação de assinaturas.

O que muda com trusted publishing e OIDC

O trusted publishing cria uma relação de confiança entre o npm e um provedor de CI/CD por meio de OpenID Connect. A autorização é vinculada ao workflow configurado, permitindo substituir credenciais de publicação de longa duração por credenciais temporárias. A documentação oficial do npm descreve os provedores suportados e os requisitos atuais.

Na configuração com GitHub Actions, confira organização, repositório, nome do arquivo de workflow e ambiente, quando utilizado. Revise também as ações permitidas ao publicador. O npm oferece publicação em estágio para revisão antes da disponibilização pública; conceder publicação direta é uma decisão adicional. Depois de verificar a migração, restringir o acesso por tokens tradicionais reduz caminhos alternativos de publicação.

OIDC remove uma credencial persistente desse caminho, mas o workflow continua sendo uma autoridade sensível. Se código não revisado puder alterar a etapa que gera o pacote ou alcançar a etapa de publicação, a confiança pode ser abusada dentro do processo autorizado.

Provenance liga o artefato à sua origem

Atestações de provenance registram informações sobre a origem e a construção do pacote. No ecossistema npm, elas permitem examinar o vínculo com o repositório e o ambiente de build. A documentação de provenance explica a assinatura com Sigstore e o registro de transparência.

Essa evidência não demonstra ausência de código malicioso. Um processo autorizado pode construir uma alteração ruim. Para o consumidor, a pergunta produtiva é se a origem e o processo observados correspondem à política de confiança da organização.

Alteração revisada
        ↓
Workflow autorizado
        ↓
Build e testes
        ↓
Pacote + digest + atestação
        ↓
Verificação pelo consumidor

Quatro controles que protegem a release

A orientação de uso seguro do GitHub Actions destaca o risco de ações de terceiros e recomenda fixá-las por SHA completo. Uma tag pode mudar de destino; o identificador de commit estabelece uma referência imutável, que ainda precisa ser revisada e atualizada quando houver correções.

Adote permissões mínimas por job, revise quem pode editar workflows e evite processar conteúdo não confiável em etapas com acesso a segredos ou autoridade de publicação. Trate caches, artefatos intermediários e dependências do build como entradas que influenciam a release, em vez de presumir que todo arquivo vindo de um job anterior é confiável.

CamadaControle propostoO que registrar
CódigoRevisão do commit efetivamente lançadoCommit, responsáveis e resultado dos testes
WorkflowAutoridade de publicação isoladaArquivo, ambiente e permissões
ArtefatoInspeção do conteúdo empacotadoLista de arquivos e digest da release
ConsumoVerificação de assinaturas e política de origemAtestações e exceções aprovadas

A referência SLSA 1.2 para produção de artefatos ajuda a avaliar integridade da provenance e isolamento do build. Seus níveis possuem requisitos específicos; uma assinatura ou um badge isolado não basta para declarar conformidade com um nível.

Como verificar sem transformar o teste em execução de dependências

Em uma cópia de análise sem credenciais de produção, examine o manifesto e o lockfile antes de instalar. Se precisar materializar dependências para inspecionar o conjunto, a opção abaixo evita os scripts de ciclo de instalação nessa etapa. Isso não torna o pacote seguro para uso posterior nem controla toda execução futura.

npm ci --ignore-scripts
npm audit signatures

O segundo comando verifica assinaturas e atestações disponíveis para as dependências instaladas. Interprete o resultado junto da origem, dos arquivos e da política adotada. A quantidade de pacotes com atestação não é uma nota de segurança do projeto.

Para revisar o que sua própria release pretende distribuir, utilize uma cópia descartável do projeto e inspecione o plano de empacotamento, sem publicar:

npm pack --dry-run --ignore-scripts

A análise proposta deve comparar esse inventário com uma lista permitida. Procure arquivos de configuração privados, dumps de teste, mapas de código com caminhos internos e credenciais esquecidas. Registre apenas os nomes e categorias necessários no relatório; não copie o conteúdo de um segredo para demonstrar que ele existe.

Laboratório fictício: um pacote legítimo com um arquivo inesperado

Imagine o pacote Aurora SDK, usado somente em um laboratório. A equipe autoriza o workflow correto e a release possui atestação válida. Entretanto, o empacotamento inclui um arquivo de fixture que deveria permanecer fora da distribuição. O cenário não representa um incidente real e não afirma que um pacote público tenha esse problema.

O teste proposto compara os arquivos planejados com o inventário aprovado. O achado deve descrever a inclusão indevida e o tipo de informação exposta, com evidência mínima. A ação corretiva seria restringir a seleção de arquivos, remover o material e gerar outra release. A assinatura anterior continua válida como registro de origem, embora o artefato não atenda à política.

Esse exercício evidencia uma divisão importante: o publicador valida o artefato antes de liberá-lo, e o consumidor verifica se o artefato recebido corresponde a uma origem aceita. As duas responsabilidades se complementam.

Perguntas frequentes

Trusted publishing impede toda publicação maliciosa?

Não. Ele melhora a autenticação do processo de publicação. Código, contas autorizadas, workflows e dependências continuam precisando de controles.

Ausência de provenance prova comprometimento?

Não. Pode refletir o processo de distribuição ou suas limitações. Ela reduz a evidência disponível para verificação e deve ser tratada conforme a política de risco.

Como registrar essa avaliação em uma auditoria?

Separe identidade, integridade, conteúdo e autorização em resultados distintos. Para organizar o trabalho, veja o guia de fluxos e evidências com CatBridge. A verificação do pipeline npm deve ser executada no ambiente de análise apropriado; não pressupõe um adaptador npm no aplicativo.

Próximo passo: escolha uma release do seu projeto e reúna commit, workflow, inventário, digest e atestação. Se esses elementos não podem ser relacionados, você encontrou uma lacuna de rastreabilidade antes de precisar discutir exploração.

Escrito por

Daniel Felipe é criador do NetCatTest e produz conteúdos sobre cibersegurança, privacidade digital, OSINT, laboratórios autorizados e ferramentas para estudo técnico responsável.

Compartilhar

Enviar este artigo