跳至主要內容
>_ITDITD網站資安平台

資安指南

osv-scanner 實務:pnpm、忽略 CVE、離線模式與常見錯誤

導入之後才會遇到的問題:pnpm-lock.yaml 支援、用 osv-scanner.toml 忽略單一 CVE、三個離線旗標及其引發的錯誤、CI 中的結束碼 0/1/127/128,以及從 v1 到 v2 改名的旗標。

發布於 2026-09-04 更新於 2026-10-06 最後核實 2026-10-06 閱讀時間 4 分鐘

適用對象:已經安裝 osv-scanner 並遇到問題的人。本文涵蓋的是導入之後才會遇到的問題,而不是安裝。所有內容都依據官方文件。

指定鎖定檔

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

當無法從檔名推斷格式時,在路徑前面加上要使用的解析器:

# 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'

為什麼用鎖定檔而不是 manifest

manifest(package.json 等)記錄的是你要求的範圍,而不是實際安裝的版本。鎖定檔記錄的是解析後的確切版本,所以掃描結果與實際安裝的內容一致。依範圍判斷再期待結果正確,是弱得多的依據。

如何檢查自己的環境

結果看起來不對時,在加更多旗標之前,先進行以下五項確認。每一項都只檢查你自己的專案。

1

確認版本

執行 osv-scanner --version。2025 年發布的 v2 改變了指令形式和多個旗標名稱,所以為 v1 寫的說明照做常常會失敗。官方文件現在以 v2 為準。
2

確認它讀了什麼

執行記錄會顯示讀取的每個檔案,以及在其中找到多少套件。確認預期的鎖定檔都有列出,而且數量沒有少得可疑。要看完整清單,使用 --format json --all-packages(--all-packages 只能搭配 JSON 輸出)。
3

確認結束碼

執行後立刻在 bash 中用 echo $?,在 PowerShell 中用 $LASTEXITCODE。各值的意義見下表。
4

確認設定實際套用

osv-scanner.toml 只套用到它所在目錄中的檔案,不會傳遞到子目錄。在用 -r 掃描的 monorepo 中,在每個鎖定檔旁邊各放一個,或用 --config 把同一個檔案套用到全部。
5

確認離線資料庫的位置和新舊

本機資料庫若有設定 OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY 就從那裡讀取,否則依序是使用者快取目錄、系統暫存目錄。其中的檔案依 osv-scanner/<ecosystem>/all.zip 的形式存放。如果它們的修改日期很舊,你的判定結果也一樣舊。

結束碼與 CI 的處理方式

結束碼官方意義在 CI 中
0找到套件,沒有符合任何已知漏洞通過
1找到套件,有符合的漏洞失敗(有檢出:修正,或設定到期日後忽略)
127一般錯誤失敗(掃描本身出錯)
128沒有找到套件(沒有讀到任何可讀的內容)失敗(修正路徑或加入鎖定檔)

文件把 1–126 保留給與結果相關的情況,129–255 保留給與結果無關的錯誤。把 CI 的處理分成三種:0 通過、1 是檢出、其他都是掃描故障,排查失敗原因會快得多。

忽略特定漏洞

在被掃描的目錄中放一個 osv-scanner.toml:

[[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(必填):漏洞識別碼
  • ignoreUntil(選填):過了這個日期就會再次回報
  • reason(選填):還是要寫,為了下一個人,而那個人通常就是你自己

--config=/path/to/config.toml 會覆蓋各目錄的設定檔,套用到所有地方。注意,忽略一個漏洞時,被視為其別名的漏洞也會一併被忽略。

每個忽略都設定到期日,而不是永久移除

沒有 ignoreUntil 的項目,就是會永久消失、沒有人再回頭看的項目。我們的規則是:每個忽略都帶有到期日和理由。日期一到它就會再次出現,延後的判斷就不會被默默遺忘。為了讓 CI 安靜而加上的無期限忽略,正是半年後變成事故的那種東西。

離線模式:三個旗標,三種用途

最容易混淆的就是這裡。

旗標作用
--offline完全離線。 用事先下載的本機資料庫判定,不會更新它,也不會把專案或相依套件的資訊傳送到任何地方
--offline-vulnerabilities只有漏洞比對是離線的;其他工作(例如遞移相依的解析)仍可能使用網路
--download-offline-databases允許取得/更新本機資料庫,只有同時設定離線旗標時才會生效

--offline

完全離線;不更新資料庫,不傳送任何資料

--offline-vulnerabilities

只有比對在本機進行;其他工作可能使用網路

--download-offline-databases(單獨使用無效)

需要搭配上面其中之一 → 單獨使用會出現 "databases can only be downloaded when running in offline mode"

三個離線旗標。--download-offline-databases 單獨使用時沒有作用,這就是大家搜尋的那個錯誤的原因。

錯誤訊息與原因

  • databases can only be downloaded when running in offline mode → 單獨傳入了 --download-offline-databases;它需要搭配離線旗標
  • 還沒有本機資料庫就使用 --offline → 會出現資料庫不存在的錯誤;第一次執行必須先取得資料庫
  • no package sources found → 該路徑下沒有任何東西被辨識為鎖定檔或 manifest;用 -L 指定,或用 -r 走訪

不靠猜測的選擇方式

  • 在隔離網路中執行 → --offline(第一次執行時加上 --download-offline-databases)
  • 只有漏洞資料必須留在本機 → --offline-vulnerabilities
  • 固定資料庫的位置 → 環境變數 OSV_SCANNER_LOCAL_DB_CACHE_DIRECTORY
  • 除錯時 → 先不加任何旗標執行,再逐步縮小範圍

v1 文章中的旗標無法使用時

許多搜尋結果是為 v1 寫的。官方遷移指南列出的主要變更:

v1v2
--experimental-offline--offline
--experimental-download-offline-databases--download-offline-databases
--experimental-call-analysis--call-analysis
--experimental-licenses 及相關旗標合併為 --licenses
--docker / -D(容器)osv-scanner scan image <image>
--json--format=json
--skip-git--include-git-root(意義相反)

osv-scanner <dir> 仍可作為 osv-scanner scan source <dir> 的簡寫。在腳本中寫出完整的 scan source,下一個讀的人更容易理解意圖。

常見錯誤與修正

常見錯誤

  • CI 把「除了 1 以外的任何結束碼」都當作成功
  • 加上 || true 讓失敗消失
  • 只在儲存庫根目錄放一個 osv-scanner.toml,以為它涵蓋子目錄
  • 只 commit 了 package.json,沒有鎖定檔
  • 以為 --offline 仍會解析 pom.xml 的遞移相依
  • 寫入忽略設定卻沒有 ignoreUntil

修正方式

  • 只在 0 時通過,讓 128(什麼都沒讀到)無法變成綠燈
  • 改用帶到期日的忽略,逐一處理個別檢出
  • 在每個目錄各放一個檔案,或用 --config 把一個檔案套用到全部
  • commit 鎖定檔(JavaScript 為 package-lock.json、pnpm-lock.yaml、yarn.lock 或 bun.lock)
  • 離線時遞移相依的解析會被停用;如果允許使用網路,就用 --offline-vulnerabilities
  • 一定加上日期和理由,到期時重新判斷

Maven 的 pom.xml 不像鎖定檔那樣列出所有解析後的版本。osv-scanner 預設使用 deps.dev 的解析器(或用 --data-source=native 改用 Maven Central)計算遞移相依關係圖。這需要網路,在 --offline 和 --no-resolve 下會被略過。在完全隔離網路的執行中,要預期結果只涵蓋 pom.xml 中直接寫明的相依套件。

實際案例:為什麼 Log4Shell 難以回答

2021 年 12 月 Log4Shell(CVE-2021-44228) 出現時,許多組織無法迅速說出自己是否受影響。他們從未自己加入 Log4j;它是透過框架和其他函式庫帶進來的。CISA 的指引要求組織全面列出已安裝的軟體,並與受影響軟體的清單比對。

套用到 osv-scanner,就是要確認兩件事:

  • 遞移相依確實有被讀取:生態系有鎖定檔就用鎖定檔,Maven 則在啟用解析的情況下執行(不是離線,也不是 --no-resolve)
  • 清單中確實包含間接引入的函式庫:用 --format json --all-packages 印出來看

漏洞公開當天能否在幾分鐘內回答「我們有沒有受影響?」,取決於事先是否把這份清單做對。

與其他工具的差異

工具讀取的資料擅長的地方
osv-scannerOSV.dev跨生態系、以鎖定檔為單位、可離線執行
npm audit / pnpm auditnpm 安全公告資料庫npm 專案立即可用,不需額外安裝
DependabotGitHub Advisory建立更新 PR:不只指出問題,還提出修正
Trivy多個來源(含 OSV)除了應用程式相依套件,也涵蓋容器映像檔和 OS 套件

只選一個才是錯誤。 資料庫不同,找到的東西也不同。我們以 pnpm audit 作為每日的自動檢查,並用 osv-scanner 進行跨鎖定檔的檢查。

本站的看法:掃描工具不會告訴你固定的版本已經過時

有一個問題只有在實際維運中才會出現。用 overrides 把遞移相依固定在某個確切版本時,那個套件就不再收到修補更新;而掃描工具只有在存在已知漏洞時才會發出提示。所以「你凍結的版本已經舊了」是沒有任何工具會回報的狀態。我們遇到這個問題三次之後,才加上自己的每日檢查,把每個固定版本與其主版本系列中最新的修補版比對。掃描工具顯示的是今天的已知漏洞;日後可能讓你暴露在風險中的狀態,需要另外的機制。

出處

接下來閱讀

FAQ

Qosv-scanner 支援 pnpm-lock.yaml 嗎?
A

支援。npm、yarn 和 pnpm 的鎖定檔都有支援。用 `osv-scanner scan source -L pnpm-lock.yaml` 直接指定一個檔案,或用 `-r` 走訪整個目錄樹。

Q如何忽略單一 CVE?
A

在被掃描的目錄中放一個 `osv-scanner.toml`,加入帶有 `id` 的 `[[IgnoredVulns]]` 項目。也可以設定 `ignoreUntil`(到期日)和 `reason`,讓例外記錄下時間和理由,而不是永遠消失。傳入 `--config=/path/to/config.toml` 會覆蓋各目錄的設定檔,套用到全部。

Q為什麼會出現「databases can only be downloaded when running in offline mode」?
A

因為 `--download-offline-databases` 只有在同時設定離線旗標時才會生效,不能單獨使用。想在執行時一併取得本機資料庫,就把它和離線旗標一起使用。

Q已經有 npm audit 和 Dependabot,還需要 osv-scanner 嗎?
A

它們讀取不同的資料庫,涵蓋的範圍也不同。npm audit 使用 npm 的安全公告資料庫,只支援 npm;Dependabot 主要在 GitHub 上提出更新建議;osv-scanner 讀取 OSV.dev,跨生態系(npm、PyPI、Go、Maven 等),以鎖定檔為單位運作,也能完全離線執行。一個抓到另一個漏掉的東西是正常的,所以把它們當作不同的工作,而不是只選一個。

QCI 應該如何處理 osv-scanner 的結束碼?
A

依官方文件:0 表示找到套件且沒有符合任何已知漏洞,1 表示找到漏洞,127 是一般錯誤,128 表示完全沒有找到套件。只把 0 當作成功。像「除了 1 以外都通過」這樣的規則,會讓 128(什麼都沒掃描)變成綠燈。

Q為什麼舊文章裡的 --experimental-offline 或 --docker 無法使用?
A

它們在 v2 中被改名或移動了。官方遷移指南把 --experimental-offline 對應到 --offline,--experimental-download-offline-databases 對應到 --download-offline-databases,--docker 對應到 `osv-scanner scan image` 指令,--json 對應到 `--format=json`。先執行 `osv-scanner --version` 確認你用的是哪個主版本。