ANSWERS · ANSWERS FOR CODING AGENTS

Batch lookup CVE IDs and GHSA IDs offline, without GitHub API rate limits

AUTHOR · XERJ documentation team · REVIEWED BY · XERJ engineering team · PUBLISHED · 2026-10-19 · UPDATED · 2026-10-20

TL;DR — To batch lookup CVE and GHSA IDs offline without GitHub API rate limits, load the signed rust-vulns advisory pack into xerj and resolve every ID in one terms query. Each answer names the source file; unknown IDs abstain. On 2026-10-19, 6 IDs took 15 ms: 4 resolved, 2 abstained. Coverage is Rust crates only.

RUN THIS XERJ COMMAND xerj --insecure --data-dir ./xerj-data Start a single-user node on localhost:9200 in its own terminal.
RUN THIS XERJ COMMAND xerj corpus add rust-vulns --from rust-vulns-pack.zip --verify-sig rust-vulns.pub Install the advisory pack after checking its signature.
RUN THIS XERJ COMMAND xerj corpus index rust-vulns Index the RustSec and OSV records into xc-rust-vulns-* indices.
RUN THIS XERJ COMMAND bash batch.sh Resolve every ID in ids.txt with one _search; print the record and source, or abstain.

Run it

Download the zip, the public key and the signature from the GitHub release pack-rust-vulns-2026-10-19. Then install the pack with a signature check.

xerj --insecure --data-dir ./xerj-data &
xerj corpus add rust-vulns --from rust-vulns-pack.zip --verify-sig rust-vulns.pub
xerj corpus index rust-vulns

The add step printed signature verified in about 1.3 s. It loaded 1,288 RustSec and 745 OSV advisories. Indexing the 2,033 advisories took 9,769 ms.

Put the IDs in a file:

CVE-2021-25900
GHSA-9q5j-jm53-v7vr
CVE-2026-35355
RUSTSEC-2023-0071
CVE-2024-24576
CVE-2099-00001

batch.sh sends all of them in one request and matches each ID against id or aliases:

ids=$(jq -R . ids.txt | jq -sc .)
curl -s 'localhost:9200/xc-rust-vulns-*/_search' -H 'content-type: application/json' -d "{
  \"size\": 100,
  \"_source\": [\"id\", \"aliases\", \"packages\", \"fixed_versions\", \"origin\", \"source_url\"],
  \"query\": {\"bool\": {\"should\": [{\"terms\": {\"id\": $ids}}, {\"terms\": {\"aliases\": $ids}}]}}
}" | jq -r --argjson ids "$ids" '
  [.hits.hits[]._source] as $h
  | $ids[] as $q
  | ($h | map(select(.id == $q or ((.aliases // []) | index($q)))) | first) as $r
  | if $r then "\($q)  \($r.id)  \(($r.packages // []) | join(","))  fixed \(($r.fixed_versions // []) | join(","))  src \($r.source_url) :: \($r.origin)"
    else "\($q)  NOT FOUND in this pack: abstain" end'

Real output, 15 ms wall time:

CVE-2021-25900  RUSTSEC-2021-0003  smallvec  fixed 0.6.14,1.6.1  src https://github.com/rustsec/advisory-db :: crates/smallvec/RUSTSEC-2021-0003.md
GHSA-9q5j-jm53-v7vr  RUSTSEC-2022-0051  lz4-sys  fixed 1.9.4  src https://github.com/rustsec/advisory-db :: crates/lz4-sys/RUSTSEC-2022-0051.md
CVE-2026-35355  GHSA-239g-2685-54x3  uu_install  fixed 0.6.0  src https://osv-vulnerabilities.storage.googleapis.com/crates.io/all.zip :: GHSA-239g-2685-54x3.json
RUSTSEC-2023-0071  RUSTSEC-2023-0071  rsa  fixed   src https://github.com/rustsec/advisory-db :: crates/rsa/RUSTSEC-2023-0071.md
CVE-2024-24576  NOT FOUND in this pack: abstain
CVE-2099-00001  NOT FOUND in this pack: abstain

RUSTSEC-2023-0071 shows no fixed version because the advisory lists none. A trailing wildcard (xc-rust-vulns-*) is the pattern that worked; see the last section for the two that did not.

Measured on 2026-10-19

MeasureValue
Packrust-vulns, 1,598,960 bytes, 2,033 advisories, built 2026-10-19
Signature check and loadabout 1.3 s
Index9,769 ms
Batch of 6 IDs, one request15 ms wall time
Resolved / abstained4 / 2
GitHub API calls after download0

How it compares

ApproachOfflineRate limitMany IDs per callSource per answerCoverage
xerj + rust-vulns packyesnone, localyes, one terms queryyes, file in advisory-db or OSVRust crates
GitHub advisory REST APInoyes, per tokenno, one cve_id per requestyesGitHub ecosystems
OSV.dev APInoservice limitsyes, querybatchyesmany ecosystems
cargo auditafter DB fetchnoneper lockfile, not per IDyesRust crates
Chat modeldependsdependsyesno, may invent an IDtraining data

When not to use xerj

FAQ

How do I batch lookup CVE IDs without the GitHub API?

Download the signed rust-vulns pack once, load it with xerj corpus add and xerj corpus index, then send all IDs in one terms query on id and aliases. Nothing calls the GitHub API after the download.

How do I avoid GitHub API rate limits when looking up advisories?

Query a local copy. The pack is a 1,598,960-byte release asset; after that every lookup is a request to your own node on localhost.

Can I search vulnerability advisories offline?

Yes, for the advisories in the pack: 2,033 records from RustSec (1,288) and OSV crates.io (745), built 2026-10-19. It covers Rust crates only.

How do I cite the source for a CVE's affected versions?

Each record carries source_url and origin, for example crates/smallvec/RUSTSEC-2021-0003.md in rustsec/advisory-db. Print them next to the fixed versions, as the script on this page does.

What happens to an ID that is not in the pack?

The script prints NOT FOUND in this pack: abstain. CVE-2024-24576, a Rust standard library CVE, was not in this crate-advisory pack and abstained.

Is there a built-in batch command?

Not yet. Many IDs per call with a per-item answer or abstain is issue #1801, open. Today the batch is one _search plus jq.

Can I use xerj code with a CVE ID instead?

Not reliably. xerj code rust-vulns "CVE-2021-25900" ranked an lz4 advisory first in our run. Exact ID matching in xerj code is issue #1788; use the terms query.

Evidence

Related