DEV Community

Wen Ping
Wen Ping

Posted on

Updating the vuln DB on an intranet: offline bundles and rollback

Intranet CI keeps returning PASSED on an image while the same image on the public network shows a pile of CRITICAL findings—do not loosen --fail-on first. Check whether the Trivy vulnerability DB is months stale, or whether an offline import left you pointing at an empty or half-written cache.

Takeaway: SCA (software composition analysis) reads Trivy’s local vulnerability DB. On networked hosts run update-trivy-db.sh. On air-gapped hosts import an offline bundle or land a manually pulled OCI DB as a whole directory. Always back up the cache directory before updating; on failure, roll the whole directory back, then run doctor. Engine binary health belongs in the offline engines / doctor article (see Reference). Below focuses on DB update and rollback.

1. Where the DB lives

Item Guidance
Default cache root $ANGUS_SECURITY_HOME/trivy-db (override with TRIVY_CACHE_DIR)
Who reads it Trivy (sca: deps / artifacts / images)
If you skip updates New CVEs never appear → false-green gates; the console may also warn on age

ANGUS_SECURITY_HOME is the tools root (bin/, engines/, rules/). Paths follow the release README.

Typical layout (from tools/README; scans read db/—do not drop trivy.db under rules/):

trivy-db/
├── db/trivy.db              # CVE store (BoltDB)
├── db/metadata.json         # metadata; doctor checks schema
├── browse.sqlite            # console CVE browser index; not required for scan path
├── java-db/                 # bare-JAR → coordinate fingerprints; not a CVE table
├── policy/                  # optional
└── fanal/                   # scan cache; safe to delete
Enter fullscreen mode Exit fullscreen mode

2. Binary health vs DB freshness

Check How Notes
Engines not stub "$ANGUS_SECURITY_HOME/bin/doctor.sh" or angus-security tools doctor Stub/missing → SCA untrustworthy
DB schema doctor vs db/metadata.json Schema mismatch can yield empty results
Age Console Rules → Vulnerability DB, or service age metrics Stale DB can still “succeed with 0 vulns”

Freshness-related service settings (exact keys follow your deploy docs; turn auto-refresh off on air-gapped hosts):

Intent Typical default Ops meaning
Auto-refresh Often on (e.g. daily update-trivy-db.sh) Must disable on air-gap or jobs keep failing
Min refresh interval Hours Avoid hammering pulls
Max age Days Banner / advisory Finding; fail-scan-on-stale-style flags may mark SCA PARTIAL

Confirm key names and defaults against your current deploy docs—do not treat one YAML revision as a fixed contract.

3. Networked hosts: direct update

"$ANGUS_SECURITY_HOME/bin/doctor.sh"
# or
angus-security tools doctor
Enter fullscreen mode Exit fullscreen mode

Backup (required before production gates):

TS=$(date +%Y%m%d%H%M%S)
CACHE="${TRIVY_CACHE_DIR:-$ANGUS_SECURITY_HOME/trivy-db}"
cp -a "$CACHE" "$CACHE.bak-$TS"
Enter fullscreen mode Exit fullscreen mode

Update:

"$ANGUS_SECURITY_HOME/bin/update-trivy-db.sh"
# CVE only, skip Java index:
# "$ANGUS_SECURITY_HOME/bin/update-trivy-db.sh" --skip-java-db
Enter fullscreen mode Exit fullscreen mode

The script needs a real trivy binary; a stub fails immediately—that is expected. If trivy is missing, run install-engines.sh first (see Reference: CLI first scan).

Acceptance:

  1. doctor no longer WARNs/FAILs on vulndb items (per script output).
  2. Rescan the same canary image known to contain an older CVE: Finding volume should match a healthy-DB baseline, not drop to zero.
  3. For JVM bare-JAR resolution, do not leave --skip-java-db on by mistake.

4. Air-gap: offline bundle

Prepare a bundle on a networked Linux host (export-offline-bundle.sh / prepare-linux-offline-bundle.sh—names follow the release), copy it in, then:

# Flags follow script --help (common shape)
"$ANGUS_SECURITY_HOME/bin/import-offline-bundle.sh" --bundle /path/to/bundle.tar.gz
"$ANGUS_SECURITY_HOME/bin/doctor.sh"
Enter fullscreen mode Exit fullscreen mode

Alternatively: update-trivy-db.sh on the builder, export with Trivy DB options, or rsync -a trivy-db/ to production.

After import: disable auto-refresh → doctor → canary sca. Do not keep blocking production gates on a failed import.

5. Air-gap alternate: manual OCI / ORAS

When the host still has a stub, or ghcr.io is blocked, pull OCI artifacts (not docker pull images) on a jump box, then copy in. Upstream refs can change—confirm against Aqua Trivy docs / your release notes:

DB Common OCI ref Unpack to
CVE ghcr.io/aquasecurity/trivy-db:2 (or documented mirror) trivy-db/db/ (trivy.db + metadata.json)
Java index ghcr.io/aquasecurity/trivy-java-db:1 trivy-db/java-db/

With a real trivy on the jump box:

CACHE=$(mktemp -d)
trivy image --download-db-only --cache-dir "$CACHE"
trivy image --download-java-db-only --cache-dir "$CACHE" || true
tar -czf trivy-db-manual.tgz -C "$CACHE" db java-db
Enter fullscreen mode Exit fullscreen mode

Land on the intranet:

DEST="${TRIVY_CACHE_DIR:-$ANGUS_SECURITY_HOME/trivy-db}"
mkdir -p "$DEST"
tar -xzf trivy-db-manual.tgz -C "$DEST"
# expect $DEST/db/trivy.db and $DEST/db/metadata.json
"$ANGUS_SECURITY_HOME/bin/doctor.sh"
Enter fullscreen mode Exit fullscreen mode

If the console CVE browser needs browse.sqlite, build the index per the runbook or POST /api/v1/vuln-db/reindex (permissions like rule packs—confirm current API). Gates care about db/, not only the browser index.

6. Rollback when it fails

Symptom Action
update-trivy-db errors mid-run Stop relying on sca gates; restore .bak-* whole directory
Findings empty after import Wrong TRIVY_CACHE_DIR; restore backup; confirm not stub; check schema
java-db → no such table: indices Empty/corrupt Java index; re-pull without skip
Disk full / permissions Clear old backups and fanal/; ensure writable cache volume
Proxy blocks OCI Mirror / bridge, or switch to offline tarball
CACHE="${TRIVY_CACHE_DIR:-$ANGUS_SECURITY_HOME/trivy-db}"
rm -rf "$CACHE"
mv "$CACHE.bak-20261019120000" "$CACHE"   # your backup name
"$ANGUS_SECURITY_HOME/bin/doctor.sh"
Enter fullscreen mode Exit fullscreen mode

Rescan the same image reference. If CRITICAL goes from present to absent with no image change, blame the DB/engine—not “we got safer.”

7. Multi-runner / multi-node

Risk Mitigation
Runner mounts another cache Unify TRIVY_CACHE_DIR or the volume
Nodes drift on DB version Ship one versioned trivy-db tarball + checksum
Scans read a half-written tree Stage aside, verify, then atomic mv; or pause sca during cutover

8. Relationship to gates

  • A stale DB makes PASSED untrustworthy.
  • Update off the release window; canary first, then restore blocking.
  • CRITICAL grey rollout: see Reference (Trivy gate). Do not set fail-on to never to hide a bad DB.
  • Treat “DB stale” advisory Findings as ops signals, not developer defects.

9. Failure table

Symptom Cause Fix
Update OK, CI still old Second cache on runner Unify env / volume
doctor PASS, scan empty Wrong target/capabilities Follow CLI first-scan; not always the DB
Air-gap still schedules pulls Auto-refresh left on Disable; use bundle/manual
Only synced browse.sqlite Confused index with CVE DB Need db/trivy.db
JVM coordinate misses Skipped Java DB Restore java-db/

FAQ

How often should we update?

On your threat-response cadence; update immediately when a high-profile CVE hits your stack. Products often expose a max-age default (days), but there is no universal “must be N days” compliance constant—follow team policy and console banners.

Do we stop the Security process?

Usually no. In-flight sca jobs may see a mid-update tree. Safer: pause sca gates or read from a frozen copy, then cut over.

How does this relate to install-engines?

install-engines installs binaries; update-trivy-db refreshes the DB. Both must be healthy. Rules use install-rules.sh.

Is the console “Update vuln DB” the same as the script?

The tools page typically schedules the same class of update (and APIs exist). Air-gap still uses bundles / manual directories. Follow current console copy and RBAC.

Summary

  • False green → check Trivy DB before loosening gates.
  • Back up the whole directory; fail → whole-directory rollback.
  • Air-gap: offline bundle or manual OCI + disable auto-refresh.
  • Unify cache versions across runners; canary before restoring blocks.

Reference articles

Top comments (0)