Você corre npm audit, e aí está:
14 vulnerabilities (3 low, 6 moderate, 4 high, 1 critical)
Bem, veja só: quatorze vulnerabilidades. Provavelmente, esse é um projeto que está parado há um mês, e você só mexeu nele talvez duas vezes. É bem provável que você nem conseguisse citar o nome desses pacotes se lhe perguntassem. Eles provavelmente vieram junto com algumas dependências diretas. O primeiro passo já é rotina a essa altura: execute npm audit fix, veja como ele resolve alguns dos problemas, feche o terminal e siga com o seu dia. Na verdade, ninguém se aprofunda em todas as quatorze vulnerabilidades.
Preguiça? Não. Cansaço? Sim, e vale a pena identificá-lo como um problema à parte, em vez de incluí-lo na afirmação de que “os desenvolvedores não se importam com segurança”, pois as duas situações exigem soluções muito diferentes.
O problema de ruído com o npm audit
npm audit É bom em uma coisa: avisar que uma vulnerabilidade conhecida aparece em algum lugar da sua árvore de dependências. Mas dizer se isso realmente importa para o seu aplicativo em execução? Isso já é outra história.
Quando um código enterrado em quatro níveis de profundidade começa a gerar uma classificação de gravidade “Alta”, o que você deve fazer com isso? O npm define a gravidade com base no impacto e na possibilidade de exploração no caso de uso mais comum, e sua aplicação pode não ser esse caso comum. Por outro lado, dizer que “nunca chamamos isso” também não é um passe livre, já que scripts de instalação e ferramentas de compilação podem executar código vulnerável antes mesmo que uma solicitação chegue à sua aplicação.
Depois, há a questão da contagem. Esse número 14 refere-se ao número de pacotes sinalizados, não a problemas distintos. Um pacote pode conter vários alertas e ainda assim ser contado apenas uma vez, e o npm também sinaliza “metavulnerabilidades”: pacotes cujo intervalo de dependências declarado só pode ser resolvido com uma versão afetada de algum componente abaixo deles. Portanto, quatorze “vulnerabilidades” podem, na verdade, ser quatro ou cinco problemas distintos apresentando-se de maneiras diferentes.
Pior ainda, as dependências de desenvolvimento são sinalizadas com exatamente a mesma urgência que o código de execução em produção. Um plug-in do ESLint vulnerável no laptop de um desenvolvedor e uma biblioteca de autenticação vulnerável exposta à internet pública não se enquadram, fundamentalmente, na mesma categoria de emergência. No entanto, isso vale para os dois lados. Uma dependência de compilação que é executada na CI, tem acesso a segredos ou influencia o artefato que você distribui não é de baixa prioridade apenas porque está localizada em devDependencies.
A ferramenta não está necessariamente com defeito; simplesmente não dispõe do contexto de execução necessário para responder à pergunta que lhe interessa.
Por que as equipes perdem a motivação
Fadiga, ansiedade, nervosismo: nada disso é exclusivo do monitoramento de dependências e feeds de CVE, mas a segurança de dependências é uma grande fonte desses três sentimentos.
A pilha de tickets parece não ter fim. Eles continuam se acumulando mais rápido do que qualquer um consegue resolver. Quando você já avaliou sua quinquagésima vulnerabilidade e quarenta e nove delas acabam sendo irrelevantes, inacessíveis ou já resolvidas em outro lugar, o rótulo de “alta gravidade” não tem mais tanto peso. Isso é fadiga de alertas.
O verdadeiro custo não está nas conversas e nos alertas; está no que fica de lado. Se todos os alertas forem tratados da mesma forma, então aquele que realmente importa também será. As revisões começam a se transformar em uma mera verificação de itens: as auditorias são executadas no CI, alguém dá uma olhada no número de alertas, mas nada é realmente revisado. Eventualmente, alguém acrescenta || true para a etapa de auditoria, de modo que o pipeline volte a ficar verde, e essa linha permaneça lá por mais tempo do que a memória de todos sobre o motivo de sua existência. Não é que ninguém tenha deixado de se importar. A lista de pendências simplesmente cresceu mais rápido do que qualquer um conseguia dar conta.
As atualizações também têm seu peso. npm audit fix limita-se a atualizações que se enquadram nos intervalos de versão declarados. Qualquer coisa fora desses intervalos, o que pode incluir uma mudança de versão principal segundo a SemVer, precisa de --force, e a própria documentação do npm adverte contra o uso indiscriminado dessa prática. Algumas falhas não têm solução automática alguma. “É só atualizar” não é uma resposta tão simples quanto parece.
Um Passe de Triagem Mais Racional
Isso não significa ignorar npm audit. Isso significa que não devemos mais tratar cada linha de saída como igualmente urgente, pois não é o caso.
Algumas coisas que realmente ajudam:
- Acessibilidade e exposição são mais importantes do que apenas a gravidade. Uma vulnerabilidade CVE crítica no código que não seja acessível em seu ambiente geralmente tem prioridade menor do que uma vulnerabilidade moderada exposta diretamente no processamento de suas solicitações. As classificações de gravidade não conhecem seu gráfico de chamadas, mas você conhece.
- Separe a produção do desenvolvimento e, em seguida, verifique o que funciona. Uma ferramenta vulnerável na fase de compilação e uma dependência vulnerável na fase de execução geralmente exigem tempos de resposta diferentes.
npm audit --omit=devÉ um primeiro passo útil, mas as ferramentas de desenvolvimento que rodam na integração contínua (CI) com credenciais, ou o código que um empacotador inclui na versão final, continuam sendo importantes. - Agrupe por pacote, não por CVE. Uma biblioteca desatualizada pode gerar vários alertas.
npm explain <package>mostra qual das suas dependências a incorporou, e geralmente é aí que está a verdadeira solução. - Estabeleça um ritmo, mas deixe uma margem de manobra. Faça uma nova auditoria semanalmente, ou de acordo com um cronograma que se alinhe ao seu ciclo de lançamento, em vez de reavaliar a prioridade das vulnerabilidades toda vez que o feed for atualizado. Aja com mais rapidez quando houver indícios de exploração ativa ou de exposição real à Internet.
- Que “não agora” seja uma resposta válida. Uma decisão documentada de adiar uma questão de baixo risco não é o mesmo que ignorá-la. Anote o motivo e quando ela será analisada novamente, e depois siga em frente.
Essa é a diferença entre a triagem e simplesmente limpar as notificações. Uma delas realmente reduz o risco.
Onde o SecureChain se encaixa
Aqui está a diferença que vale a pena deixar bem clara: npm audit tem caráter informativo. Ele indica o que está errado e npm audit fix cuida das correções fáceis, mas as decisões difíceis ainda cabem a você. É sua função determinar se uma atualização é válida e segura, se um patch precisa ser adaptado para versões anteriores ou se um pacote em fim de vida útil (EOL) está, de fato, recebendo correções no código-fonte original.
SecureChain atua na origem desse problema, em vez de apenas aumentar a pilha de alertas. O registro público disponibiliza qualquer arquivo tar que um mantenedor tenha publicado. As assinaturas do registro comprovam que ele não sofreu alterações desde então, mas, a menos que o pacote venha acompanhado de um atestado de proveniência, nada o vincula ao repositório de código-fonte. O SecureChain recompila pacotes a partir de código-fonte verificado em ambientes isolados e fortificados e os analisa em busca de malware e código suspeito antes que cheguem à sua árvore de dependências. npm audit não foi projetado para detectar typosquats, contas de mantenedores invadidas ou scripts de instalação maliciosos por conta própria; ele apenas relata o que já consta nos dados dos alertas. Os patches seguem os tempos de resposta alvo publicados, independentemente de o desenvolvedor original ainda estar lançando correções ou ter deixado de se manifestar, e quando um pacote fica meses sem um lançamento do desenvolvedor original, Suporte contínuo ao longo do ciclo de vida continua lançando correções para a versão que você já utiliza.
Nada disso faz com que a triagem desapareça. O que muda é o grau de incerteza com que você lida antes que um pacote chegue à sua compilação. Os pacotes são compilados e assinados para atender ao SLSA Nível 3 e vêm com dados VEX e, dependendo do pacote, SBOMs. Essa é a parte que ninguém quer fazer manualmente, mas que a maioria das equipes acaba precisando para uma auditoria. O VEX aborda de forma mais direta o problema do ruído, já que especifica quais CVEs conhecidas realmente afetam uma versão específica do pacote.
A nova perspectiva que importa aqui: o SecureChain não é mais um feed competindo pela sua atenção. Significa que, para começar, há menos itens chegando à sua fila, pois grande parte do problema já foi resolvida antes mesmo de se tornar um problema para você.
