Guias de Segurança
osv-scanner na prática — pnpm, ignorar CVEs, modo offline e os erros que aparecem
As dúvidas do segundo dia: suporte a pnpm-lock.yaml, ignorar um CVE pelo osv-scanner.toml, as três flags offline e o erro que elas causam, os códigos de saída 0/1/127/128 no CI e as flags renomeadas da v1 para a v2.
Para quem é: pessoas que já instalaram o osv-scanner e esbarraram em problemas. Isto cobre as dúvidas do segundo dia, não a instalação. Tudo aqui segue a documentação oficial.
Apontando para um lockfile
# a single lockfile
osv-scanner scan source -L pnpm-lock.yaml
# walk a directory
osv-scanner scan source -r ./my-project/Quando o formato não pode ser deduzido pelo nome do arquivo, prefixe o caminho com o parser a usar:
# parse an oddly named file as requirements.txt
osv-scanner scan source -L 'requirements.txt:/path/to/extra-requirements.txt'
# path containing a colon — lead with a bare ':' to keep filename inference
osv-scanner scan source -L ':/path/to/my:projects/package-lock.json'Por que o lockfile e não o manifesto
Um manifesto (package.json e similares) registra a faixa que você pediu, não o que de fato foi instalado. Um lockfile traz versões exatas e resolvidas, então a varredura corresponde ao que realmente está na árvore. Julgar uma faixa e torcer é uma evidência bem mais fraca.
Como verificar o seu próprio ambiente
Quando os resultados parecem errados, passe por estas cinco verificações antes de adicionar mais flags. Cada uma só inspeciona o seu próprio projeto.
Verifique a versão
osv-scanner --version. A v2, lançada em 2025, mudou o formato dos comandos e vários nomes de flags, então instruções escritas para a v1 muitas vezes falham do jeito que estão. A documentação oficial agora é voltada para a v2.Verifique o que ele leu
--format json --all-packages (--all-packages só funciona com saída JSON).Verifique o código de saída
echo $? no bash ou $LASTEXITCODE no PowerShell. A tabela abaixo dá os significados.Verifique se a configuração realmente valeu
osv-scanner.toml só se aplica aos arquivos do diretório onde ele está; ele não se propaga para subdiretórios. Num monorepo varrido com -r, coloque um ao lado de cada lockfile ou passe um único arquivo para tudo com --config.Verifique onde fica o banco offline e a idade dele
OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY, se definido; senão, do diretório de cache do usuário e, depois, do diretório temporário do sistema. Dentro dele, os arquivos seguem osv-scanner/<ecosystem>/all.zip. Se as datas de modificação forem antigas, o seu veredito também é.Códigos de saída e como o CI deve tratá-los
| Código de saída | Significado oficial | No CI |
|---|---|---|
0 | Pacotes encontrados, nenhuma vulnerabilidade conhecida casou | Passa |
1 | Pacotes encontrados, vulnerabilidades casaram | Falha (um achado: corrija ou ignore com validade) |
127 | Erro geral | Falha (a própria varredura quebrou) |
128 | Nenhum pacote encontrado (nada legível foi pego) | Falha (corrija o caminho ou adicione o lockfile) |
A documentação reserva 1–126 para resultados relacionados à varredura e 129–255 para erros não relacionados aos resultados. Dividir o tratamento no CI em três — 0 passa, 1 é um achado, qualquer outro é uma varredura quebrada — torna as falhas muito mais rápidas de diagnosticar.
Ignorando uma vulnerabilidade específica
Coloque um osv-scanner.toml no diretório que está sendo varrido:
[[IgnoredVulns]]
id = "GHSA-xxxx-xxxx-xxxx"
ignoreUntil = 2026-12-31
reason = "Feature is not used and the code path is unreachable; re-evaluate at the December inventory"id(obrigatório): o identificador da vulnerabilidadeignoreUntil(opcional): depois dessa data ela volta a ser reportadareason(opcional): escreva mesmo assim — para a próxima pessoa, que geralmente é você
--config=/path/to/config.toml substitui os arquivos por diretório e vale em todo lugar. Note que ignorar uma vulnerabilidade também ignora as tratadas como aliases dela.
Dê a toda exceção uma data de validade em vez de removê-la para sempre
Uma entrada sem ignoreUntil é um item que some permanentemente e que ninguém revisita. A nossa regra: toda exceção tem uma validade e um motivo — quando a data passa ela volta, então a decisão adiada não pode ser esquecida em silêncio. Exceções sem prazo adicionadas para calar o CI são exatamente o que vira um incidente seis meses depois.
Modo offline: três flags, três funções
É aqui que mora a maior parte da confusão.
| Flag | O que faz |
|---|---|
--offline | Totalmente offline. Julga contra um banco de dados local baixado antes, não o atualiza e não envia nenhuma informação do projeto ou das dependências para lugar nenhum |
--offline-vulnerabilities | Só a correspondência de vulnerabilidades é offline; outros trabalhos (como a resolução transitiva) ainda podem usar a rede |
--download-offline-databases | Permite baixar/atualizar o banco local — só faz efeito quando uma flag offline também está definida |
--offline
totalmente offline; sem atualização do banco, nada enviado
--offline-vulnerabilities
só a correspondência é local; outros trabalhos podem usar a rede
--download-offline-databases (inerte sozinha)
precisa de uma das anteriores → sozinha você recebe "databases can only be downloaded when running in offline mode"
Os erros e o que os causa
databases can only be downloaded when running in offline mode→--download-offline-databasesfoi passada sozinha; ela precisa de uma flag offline junto--offlineainda sem banco de dados local → você recebe um erro dizendo que o banco está faltando; a primeira execução precisa baixá-lono package sources found→ nada naquele caminho foi reconhecido como lockfile ou manifesto; indique-o com-Lou percorra com-r
Escolhendo sem chutar
- Execução isolada da rede →
--offline(mais--download-offline-databasesna primeira execução) - Só os dados de vulnerabilidade precisam ficar locais →
--offline-vulnerabilities - Fixar onde o banco fica → a variável de ambiente
OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY - Depuração → rode primeiro sem flags, depois afunile
Quando flags de um artigo da v1 não funcionam
Muitos resultados de busca foram escritos para a v1. As principais mudanças listadas no guia oficial de migração:
| v1 | v2 |
|---|---|
--experimental-offline | --offline |
--experimental-download-offline-databases | --download-offline-databases |
--experimental-call-analysis | --call-analysis |
--experimental-licenses e relacionadas | unificadas em --licenses |
--docker / -D (containers) | osv-scanner scan image <image> |
--json | --format=json |
--skip-git | --include-git-root (sentido invertido) |
osv-scanner <dir> ainda funciona como atalho para osv-scanner scan source <dir>. Escrever scan source por extenso em scripts deixa a intenção clara para o próximo leitor.
Erros comuns e como corrigi-los
Erros comuns
- O CI trata "qualquer código de saída exceto 1" como sucesso
|| trueadicionado para fazer as falhas sumirem- Um único
osv-scanner.tomlna raiz do repositório, presumindo que cobre os subdiretórios - Só o
package.jsoncommitado, sem lockfile - Presumir que
--offlineainda resolve as dependências transitivas de umpom.xml - Exceções escritas sem
ignoreUntil
A correção
- Passe só com 0, para que o 128 (nada lido) não fique verde
- Cale achados individuais com exceções que expiram
- Coloque um arquivo em cada diretório ou aplique um para tudo com
--config - Commite o lockfile (em JavaScript:
package-lock.json,pnpm-lock.yaml,yarn.lockoubun.lock) - A resolução transitiva fica desativada offline; se a rede for permitida, use
--offline-vulnerabilities - Sempre adicione uma data e um motivo, e decida de novo quando a data chegar
Um pom.xml do Maven não lista todas as versões resolvidas como um lockfile faz. Por padrão, o osv-scanner calcula o grafo transitivo usando o resolvedor do deps.dev (ou o Maven Central com --data-source=native). Isso precisa da rede e é pulado com --offline e --no-resolve. Numa execução totalmente isolada da rede, espere que os resultados cubram só as dependências escritas diretamente no pom.xml.
Um exemplo real: por que o Log4Shell foi difícil de responder
Quando o Log4Shell (CVE-2021-44228) apareceu em dezembro de 2021, muitas organizações não conseguiram dizer rapidamente se eram afetadas. Elas nunca tinham adicionado o Log4j por conta própria; ele chegava por meio de frameworks e outras bibliotecas. A orientação da CISA pedia que as organizações levantassem de forma abrangente o software instalado e o comparassem com a lista de software afetado.
Aplicado ao osv-scanner, isso significa verificar duas coisas:
- As dependências transitivas estão de fato sendo lidas: lockfiles onde o ecossistema os tem e, no Maven, uma execução com a resolução ativada (não offline, sem
--no-resolve) - O inventário realmente contém as bibliotecas que chegam indiretamente — imprima-o com
--format json --all-packagese confira
Conseguir responder "somos afetados?" em minutos no dia da divulgação depende de ter esse inventário certo de antemão.
Em que difere das ferramentas vizinhas
| Ferramenta | Dados que lê | No que é boa |
|---|---|---|
| osv-scanner | OSV.dev | Vários ecossistemas, por lockfile, pode rodar offline |
npm audit / pnpm audit | Banco de avisos do npm | Imediato para projetos npm, nada extra para instalar |
| Dependabot | GitHub Advisory | Abre PRs de atualização — propõe a correção, não só o achado |
| Trivy | Vários (incl. OSV) | Imagens de container e pacotes do SO, além das dependências do app |
Escolher exatamente uma é o erro. Bancos de dados diferentes revelam coisas diferentes. Nós rodamos o pnpm audit como verificação automática diária e usamos o osv-scanner para verificações entre lockfiles.
A visão deste site: um scanner não avisa que o seu pin ficou desatualizado
Um problema só aparece na operação real. Quando você fixa uma dependência transitiva numa versão exata com overrides, esse pacote deixa de receber atualizações de patch — e um scanner só se manifesta quando existe uma vulnerabilidade conhecida. Então "a versão que você congelou agora está velha" é um estado que ninguém reporta. Passamos por isso três vezes antes de adicionar a nossa própria verificação diária, que compara cada pin com o patch mais recente da sua linha principal. Um scanner mostra as vulnerabilidades conhecidas hoje; condições que tendem a deixar você exposto depois precisam de outro mecanismo.
Fontes
- Documentação do OSV-Scanner — Usage / Offline Mode / Configuration
- Supported Artifacts and Manifests
- Documentação do OSV-Scanner — Output (formatos e códigos de saída) / Migration Guide (v1 para v2)
- CISA — Apache Log4j Vulnerability Guidance
Leia a seguir
- Primeiros passos: instalando e usando o osv-scanner
- Priorização: decidindo o que corrigir primeiro (CVSS, EPSS, KEV)
- Incidente: Log4Shell (quando dependências transitivas esconderam o que estava em uso)
- Prática: a prática da resposta a vulnerabilidades / defesa contra worms na cadeia de suprimentos do npm (em inglês)
FAQ
QO osv-scanner suporta pnpm-lock.yaml?
Sim. Lockfiles de npm, yarn e pnpm são todos suportados. Aponte para um diretamente com `osv-scanner scan source -L pnpm-lock.yaml` ou percorra uma árvore com `-r`.
QComo ignoro um único CVE?
Coloque um `osv-scanner.toml` no diretório varrido e adicione uma entrada `[[IgnoredVulns]]` com o `id`. Você também pode definir `ignoreUntil` (uma data de validade) e `reason`, para que a exceção registre quando e por quê, em vez de sumir para sempre. Passar `--config=/path/to/config.toml` substitui os arquivos por diretório e vale para tudo.
QPor que recebo 'databases can only be downloaded when running in offline mode'?
Porque `--download-offline-databases` só faz efeito quando uma flag offline também está definida — ela não pode ser usada sozinha. Combine-a com a flag offline quando quiser que o banco de dados local seja baixado como parte da execução.
QSe eu já tenho npm audit e Dependabot, preciso do osv-scanner?
Eles leem bancos de dados diferentes e cobrem terrenos diferentes. O npm audit usa o banco de avisos do npm e só serve para npm; o Dependabot propõe principalmente atualizações no GitHub; o osv-scanner lê o OSV.dev em vários ecossistemas (npm, PyPI, Go, Maven e outros), trabalha por lockfile e pode rodar totalmente offline. É normal um pegar algo que o outro deixa passar, então trate-os como funções diferentes em vez de escolher um.
QComo o CI deve tratar os códigos de saída do osv-scanner?
Segundo a documentação oficial: 0 significa que pacotes foram encontrados e nenhum casou com uma vulnerabilidade conhecida, 1 significa que vulnerabilidades foram encontradas, 127 é um erro geral e 128 significa que nenhum pacote foi encontrado. Trate só o 0 como sucesso. Uma regra como 'tudo menos 1 passa' transforma o 128 — nada foi varrido — num sinal verde.
QPor que --experimental-offline ou --docker de artigos antigos não funcionam?
Foram renomeados ou movidos na v2. O guia oficial de migração mapeia --experimental-offline para --offline, --experimental-download-offline-databases para --download-offline-databases, --docker para o comando `osv-scanner scan image` e --json para `--format=json`. Rode `osv-scanner --version` primeiro para ver qual versão principal você tem.