Saltar al contenido
>_ITDITDPlataforma de seguridad web

Guías de seguridad

osv-scanner en la práctica: pnpm, ignorar CVE, modo sin conexión y los errores que te encuentras

Las preguntas del segundo día: soporte de pnpm-lock.yaml, ignorar un CVE con osv-scanner.toml, las tres opciones sin conexión y el error que provocan, los códigos de salida 0/1/127/128 en CI y las opciones que cambiaron de nombre de la v1 a la v2.

Publicado 2026-09-04 Actualizado 2026-10-06 Última verificación 2026-10-06 12 min de lectura

Para quién es: personas que ya han instalado osv-scanner y se han topado con problemas. Esto cubre las preguntas del segundo día, no la instalación. Todo lo que sigue se basa en la documentación oficial.

Apuntar a un lockfile

# a single lockfile
osv-scanner scan source -L pnpm-lock.yaml
 
# walk a directory
osv-scanner scan source -r ./my-project/

Cuando el formato no se puede deducir del nombre del archivo, antepón a la ruta el analizador que debe usarse:

# 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 qué el lockfile y no el manifiesto

Un manifiesto (package.json y similares) registra el rango que pediste, no lo que se instaló de verdad. Un lockfile contiene las versiones exactas resueltas, así que el escaneo coincide con lo que realmente hay en el árbol. Juzgar un rango y esperar que salga bien es una prueba mucho más débil.

Cómo comprobar tu propia configuración

Cuando los resultados parezcan incorrectos, pasa por estas cinco comprobaciones antes de añadir más opciones. Cada una solo inspecciona tu propio proyecto.

1

Comprueba la versión

Ejecuta osv-scanner --version. La v2, publicada en 2025, cambió la forma de los comandos y el nombre de varias opciones, así que las instrucciones escritas para la v1 a menudo fallan tal cual. La documentación oficial está ahora orientada a la v2.
2

Comprueba qué leyó

El registro de la ejecución muestra cada archivo que leyó y cuántos paquetes encontró en él. Confirma que aparecen los lockfiles que esperabas y que las cifras no son sospechosamente bajas. Para el inventario completo, usa --format json --all-packages (--all-packages solo funciona con salida JSON).
3

Comprueba el código de salida

Justo después de la ejecución, usa echo $? en bash o $LASTEXITCODE en PowerShell. La tabla de abajo da los significados.
4

Comprueba la configuración que se aplicó de verdad

Un osv-scanner.toml solo se aplica a los archivos del directorio donde está; no se propaga a los subdirectorios. En un monorepo escaneado con -r, pon uno junto a cada lockfile, o pasa un único archivo a todo con --config.
5

Comprueba dónde está la base de datos sin conexión y su antigüedad

La base de datos local se lee de OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY si está definida; si no, del directorio de caché del usuario y, después, del directorio temporal del sistema. Dentro, los archivos siguen la forma osv-scanner/<ecosystem>/all.zip. Si sus fechas de modificación son antiguas, también lo es tu veredicto.

Códigos de salida y cómo debe tratarlos CI

Código de salidaSignificado oficialEn CI
0Se encontraron paquetes, ninguna vulnerabilidad conocida coincidióPasa
1Se encontraron paquetes, hubo vulnerabilidades que coincidieronFalla (un hallazgo: corrígelo o ignóralo con caducidad)
127Error generalFalla (el propio escaneo se rompió)
128No se encontraron paquetes (no se recogió nada legible)Falla (corrige la ruta o añade el lockfile)

La documentación reserva 1–126 para resultados relacionados con el escaneo y 129–255 para errores no relacionados con los resultados. Dividir el tratamiento en CI en tres —0 pasa, 1 es un hallazgo, cualquier otro es un escaneo roto— hace que los fallos se diagnostiquen mucho más rápido.

Ignorar una vulnerabilidad concreta

Coloca un osv-scanner.toml en el directorio que se escanea:

[[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 (obligatorio): el identificador de la vulnerabilidad
  • ignoreUntil (opcional): a partir de esta fecha se vuelve a informar
  • reason (opcional): escríbelo de todos modos, para la siguiente persona, que normalmente eres tú

--config=/path/to/config.toml sustituye a los archivos de cada directorio y se aplica en todas partes. Ten en cuenta que ignorar una vulnerabilidad también ignora las que se tratan como sus alias.

Ponle a cada exclusión una fecha de caducidad en lugar de eliminarla para siempre

Una entrada sin ignoreUntil es un elemento que desaparece para siempre y que nadie vuelve a revisar. Nuestra regla es: cada exclusión lleva una caducidad y un motivo; cuando pasa la fecha vuelve a aparecer, así que la decisión aplazada no puede olvidarse sin más. Las exclusiones sin fecha añadidas para silenciar CI son justo lo que se convierte en un incidente seis meses después.

Modo sin conexión: tres opciones, tres funciones

Aquí es donde está la mayor parte de la confusión.

OpciónQué hace
--offlineTotalmente sin conexión. Juzga frente a una base de datos local descargada previamente, no la actualiza y no envía información del proyecto ni de las dependencias a ninguna parte
--offline-vulnerabilitiesSolo el cruce de vulnerabilidades es sin conexión; otras tareas (como la resolución de dependencias transitivas) pueden seguir usando la red
--download-offline-databasesPermite descargar/actualizar la base de datos local; solo surte efecto cuando también hay una opción sin conexión activada

--offline

totalmente sin conexión; no actualiza la base de datos ni envía nada fuera

--offline-vulnerabilities

solo el cruce es local; otras tareas pueden usar la red

--download-offline-databases (inerte sola)

necesita una de las anteriores → sola obtienes "databases can only be downloaded when running in offline mode"

Las tres opciones sin conexión. --download-offline-databases no hace nada por sí sola, y eso provoca el error que la gente busca.

Los errores y qué los provoca

  • databases can only be downloaded when running in offline mode → se pasó --download-offline-databases sola; necesita una opción sin conexión al lado
  • --offline sin base de datos local todavía → recibes un error que dice que falta la base de datos; la primera ejecución tiene que descargarla
  • no package sources found → nada en esa ruta se reconoció como lockfile o manifiesto; nómbralo con -L o recorre con -r

Elegir sin adivinar

  • Ejecución aislada de la red → --offline (más --download-offline-databases en la primera ejecución)
  • Solo los datos de vulnerabilidades deben quedarse en local → --offline-vulnerabilities
  • Fijar dónde vive la base de datos → la variable de entorno OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY
  • Depurar → ejecuta primero sin opciones y luego acota

Cuando no funcionan las opciones de un artículo de la v1

Muchos resultados de búsqueda se escribieron para la v1. Los principales cambios que recoge la guía oficial de migración:

v1v2
--experimental-offline--offline
--experimental-download-offline-databases--download-offline-databases
--experimental-call-analysis--call-analysis
--experimental-licenses y relacionadasunificadas en --licenses
--docker / -D (contenedores)osv-scanner scan image <image>
--json--format=json
--skip-git--include-git-root (significado invertido)

osv-scanner <dir> sigue funcionando como atajo de osv-scanner scan source <dir>. Escribir scan source completo en los scripts deja clara la intención al siguiente que los lea.

Errores frecuentes y cómo corregirlos

Errores frecuentes

  • CI trata «cualquier código de salida salvo 1» como éxito
  • Añadir || true para que los fallos desaparezcan
  • Un único osv-scanner.toml en la raíz del repositorio, dando por hecho que cubre los subdirectorios
  • Solo package.json en el repositorio, sin lockfile
  • Dar por hecho que --offline sigue resolviendo las dependencias transitivas de un pom.xml
  • Exclusiones escritas sin ignoreUntil

La corrección

  • Pasar solo con 0, para que el 128 (no se leyó nada) no pueda salir en verde
  • Silenciar hallazgos concretos con exclusiones con caducidad
  • Poner un archivo en cada directorio, o aplicar uno a todo con --config
  • Subir el lockfile al repositorio (en JavaScript: package-lock.json, pnpm-lock.yaml, yarn.lock o bun.lock)
  • La resolución transitiva está desactivada sin conexión; si se permite la red, usa --offline-vulnerabilities
  • Añadir siempre una fecha y un motivo, y volver a decidir cuando llegue la fecha

Un pom.xml de Maven no enumera todas las versiones resueltas como hace un lockfile. Por defecto, osv-scanner calcula el grafo transitivo con el resolvedor de deps.dev (o con Maven Central usando --data-source=native). Eso necesita la red y se omite con --offline y --no-resolve. En una ejecución totalmente aislada de la red, cuenta con que los resultados cubran solo las dependencias escritas directamente en el pom.xml.

Un caso real: por qué costó responder ante Log4Shell

Cuando apareció Log4Shell (CVE-2021-44228) en diciembre de 2021, muchas organizaciones no pudieron decir rápidamente si estaban afectadas. Nunca habían añadido Log4j ellas mismas; llegaba a través de frameworks y otras bibliotecas. La guía de CISA pedía a las organizaciones inventariar de forma exhaustiva el software instalado y compararlo con la lista de software afectado.

Aplicado a osv-scanner, eso significa comprobar dos cosas:

  • Que de verdad se leen las dependencias transitivas: lockfiles donde el ecosistema los tiene y, para Maven, una ejecución con la resolución activada (sin conexión no, y sin --no-resolve)
  • Que el inventario contiene de verdad las bibliotecas que llegan de forma indirecta: imprímelo con --format json --all-packages y míralo

Poder responder «¿nos afecta?» en minutos el día de la divulgación depende de tener ese inventario bien hecho de antemano.

En qué se diferencia de las herramientas vecinas

HerramientaDatos que leeEn qué destaca
osv-scannerOSV.devVarios ecosistemas, por lockfile, puede funcionar sin conexión
npm audit / pnpm auditBase de datos de avisos de npmInmediato para proyectos npm, no hay que instalar nada más
DependabotGitHub AdvisoryAbre PR de actualización: propone la corrección, no solo el hallazgo
TrivyVarias (incl. OSV)Imágenes de contenedor y paquetes del sistema operativo, además de las dependencias de la app

Elegir exactamente una es el error. Bases de datos distintas sacan a la luz cosas distintas. Nosotros ejecutamos pnpm audit como comprobación automática diaria y usamos osv-scanner para comprobaciones entre lockfiles.

La visión de este sitio: un escáner no te dirá que tu versión fijada se quedó antigua

Hay un problema que solo aparece en la operación real. Cuando fijas una dependencia transitiva a una versión exacta con overrides, ese paquete deja de recibir actualizaciones de parche, y un escáner solo avisa cuando existe una vulnerabilidad conocida. Así que «la versión que congelaste ya es antigua» es un estado del que nadie informa. Nos pasó tres veces antes de añadir nuestra propia comprobación diaria, que compara cada versión fijada con el parche más reciente de su línea principal. Un escáner muestra las vulnerabilidades conocidas hoy; las condiciones que probablemente te dejen expuesto más adelante necesitan otro mecanismo.

Fuentes

Sigue leyendo

FAQ

Q¿osv-scanner soporta pnpm-lock.yaml?
A

Sí. Los lockfiles de npm, yarn y pnpm están todos soportados. Apunta a uno directamente con `osv-scanner scan source -L pnpm-lock.yaml`, o recorre un árbol con `-r`.

Q¿Cómo ignoro un solo CVE?
A

Pon un `osv-scanner.toml` en el directorio escaneado y añade una entrada `[[IgnoredVulns]]` con el `id`. También puedes fijar `ignoreUntil` (una fecha de caducidad) y `reason`, para que la excepción deje constancia de cuándo y por qué en lugar de desaparecer para siempre. Pasar `--config=/path/to/config.toml` sustituye a los archivos de cada directorio y se aplica a todo.

Q¿Por qué recibo 'databases can only be downloaded when running in offline mode'?
A

Porque `--download-offline-databases` solo surte efecto cuando también hay una opción sin conexión activada; no se puede usar sola. Combínala con la opción sin conexión cuando quieras que la base de datos local se descargue durante la ejecución.

QSi ya tengo npm audit y Dependabot, ¿necesito osv-scanner?
A

Leen bases de datos distintas y cubren terrenos distintos. npm audit usa la base de datos de avisos de npm y solo sirve para npm; Dependabot sobre todo propone actualizaciones en GitHub; osv-scanner lee OSV.dev en varios ecosistemas (npm, PyPI, Go, Maven y más), trabaja por lockfile y puede funcionar completamente sin conexión. Es normal que uno detecte algo que el otro no, así que trátalos como trabajos distintos en lugar de elegir uno.

Q¿Cómo debe tratar CI los códigos de salida de osv-scanner?
A

Según la documentación oficial: 0 significa que se encontraron paquetes y ninguno coincidió con una vulnerabilidad conocida, 1 que se encontraron vulnerabilidades, 127 es un error general y 128 significa que no se encontró ningún paquete. Trata solo el 0 como éxito. Una regla como 'todo lo que no sea 1 pasa' convierte el 128 (no se escaneó nada) en una marca verde.

Q¿Por qué no funcionan --experimental-offline o --docker de artículos antiguos?
A

Cambiaron de nombre o de sitio en la v2. La guía oficial de migración asigna --experimental-offline a --offline, --experimental-download-offline-databases a --download-offline-databases, --docker al comando `osv-scanner scan image` y --json a `--format=json`. Ejecuta primero `osv-scanner --version` para ver qué versión principal tienes.