Docker Security Scanner / qdrant/qdrant / latest / detailed

qdrant/qdrant:latest

CRITICAL · 88/100 · now✓ Trusted source · Vendor image · QdrantScanned Jul 16–17, 2026 · Trivy DB 2026-07-08 · base Debian 13.5 · runs as root
88
/100
now
Current threat score
CRITICAL
4 Critical · 26 High findings
The image as shipped today, before any hardening — see the last box below for the score after the Wolfi rebuild.
Verdict & recommended action
Risky as shipped

A Rust vector-database server shipped on a full Debian 13.5 base and running as root by default: 233 vulnerability findings (102 unique CVEs), 4 Critical and 26 High. The danger is not in qdrant's own code — it is the fat Debian base. Three of the four Criticals sit in perl-base, which a Rust binary never invokes; the fourth is a test framework (vitest) recorded in the dashboard's build SBOM. Do not deploy it as-is, as root, on this base.

Concretely: 212 of the findings live in the Debian OS layer — perl, util-linux, pam, ncurses, glibc — packages a single-binary server never runs, but they arm any attacker who reaches a shell and fail every compliance scan. 15 come from the web dashboard's build SBOM (Node/build tools, not browser-executable). 6 are Rust cargo crates compiled into the binary — the only genuinely embedded residue. 0 findings are in CISA KEV and EPSS is low across the set — high on paper, no current mass-exploitation.

233
Total findings
as scanned · 102 unique CVEs
→ CVE log
−
46
OS patched
apt upgrade clears them
→ Hardening
−
166
Base bloat removed
Wolfi base = 0 OS CVEs
→ Hardening
−
15
npm dashboard
API-only build removes it
→ Residue
=
6
residual
LOW risk
0 Critical · 1 High after rebuild
Tip: each box links to its section. The reduction is two real moves — rebase to Wolfi (OS layer → 0) and drop the web dashboard (npm → 0). The last figure is the count of genuinely-embedded residual findings, not a scanner trick.
What the runbook contains (Фазы 0–8)
  1. 0
    Eligibility gate
    qdrant is Debian + Rust → fails the strict Alpine+Go gate; we proceed in fixability mode, disclosed honestly
  2. 1
    Tooling
    Trivy, Syft (SBOM), cosign v2.4.1, Docker; EPSS/KEV enrichment — no Rust binary-reachability tool exists
  3. 2
    Initial scan & baseline
    233 findings / 102 CVEs; functional baseline probed (healthz, collections, vector search) before touching anything

Everything an AI agent needs to run the hardening around this button end-to-end — three rebuilds, each built and re-scanned, with a functional parity gate.

Note: the Wolfi rebuild removes the OS layer by construction — the 3 perl Criticals are gone, not hidden. The 6 cargo residual stay until an upstream qdrant rebuild.

  1. 3
    Hardening — 3 rebuilds
    trixie-slim → Wolfi → Wolfi API-only, each built and re-scanned; 233 → 6, all 4 Criticals eliminated
  2. 4-5
    Residue & VEX / SBOM
    trace where each residual finding physically lives; honest VEX scoped by evidence level; SBOM kept, cosign verified
  3. 6-8
    Evidence & parity gate
    artifacts recorded; vector create / upsert / search all 200 on the hardened non-root read-only runtime

Hardening

Three rebuilds, each built and re-scanned. The Wolfi rebase — not a Debian patch — is what clears the OS layer.
233
Original
6
Hardened v3
BuildBaseFindingsCritHighWhat changed
OriginalDebian 13.5233426—
Hardened v1trixie-slim + apt upgrade187423OS patch; base bloat stays (perl is Essential on Debian)
Hardened v2Wolfi (Chainguard)2115OS layer → 0 CVEs; all 3 perl Criticals gone
Hardened v3Wolfi, API-only601+ web dashboard removed (drops all 15 npm incl. the vitest Critical)
1
v1 — Debian trixie-slim + apt upgrade
Clears the 46 patchable OS findings and drops 4 packages absent from slim (openssl/lzma — qdrant uses rustls, no libssl needed). Honest correction: perl-base and util-linux are Essential in Debian and cannot be removed — the base bloat and the 3 perl Criticals remain here.
233 → 187 · Criticals stay
2
v2 — Rebase to Wolfi (Chainguard)
Wolfi is glibc 2.43 (≥ trixie's 2.41), so the Rust binary runs without recompilation. It ships no perl / util-linux / pam, so the base bloat — and all 3 perl Criticals — are gone by construction, not hidden. Only apk add libunwind libgcc was needed for the binary's runtime deps.
OS layer → 0 CVEs · 233 → 21
3
v3 — Wolfi, API-only (remove the dashboard)
Additionally removes the web dashboard (/qdrant/static, 16.5 MB). This drops all 15 npm findings — including the vitest Critical — because the component is genuinely gone, not merely re-classified.
→ 6 findings · 0 Critical
4
Runtime hardening (all three builds)
non-root uid 10001, --read-only, --cap-drop ALL, --security-opt no-new-privileges, --memory 1g --cpus 2, telemetry disabled, writable paths on tmpfs.
fixes the root default
Result: 233 → 6 findings · threat band CRITICAL → LOW, all 4 Criticals eliminated. What remains is 6 Rust crates compiled into the binary — fixable only by an upstream cargo update.

Reachability / residue analysis

Honest scope: qdrant is Rust/npm, so no Go call-graph reachability applies (govulncheck is Go-only). Instead we traced where each residual finding physically lives.
−227
Removed by rebuild
6
Genuinely embedded
Method: no Rust binary-mode reachability tool exists analogous to govulncheck-for-Go. Residue assessed by where the code physically lives (image inspection of the SBOMs) + severity + EPSS/KEV + package nature. The bundle grep is indicative, not proof.
Affected — embedded6

Rust cargo crates compiled into the binary

From /qdrant/qdrant.spdx.json — an SBOM documenting crates compiled into the 82 MB binary (pyo3, serde_with, rand). They are real and present; find for their code is moot (it lives in the binary). Marked honestly affected — the only fix is an upstream cargo update.
Build-only / Node-only14

npm findings that are not browser-executable

From /qdrant/static/qdrant-web-ui.spdx.json — the dashboard's build SBOM. find for node_modules/vitest returned nothing: these are not shipped as code, the dashboard is pre-compiled static JS. The Critical (vitest) and all Highs are build tools or Node-only libraries — see the full triage in npm dashboard analysis.
Possibly bundled1

js-yaml (Medium) — under investigation

The one npm package with a hit in the compiled bundle (1 grep match). A rigorous verdict needs the bundle's import graph — left as under_investigation rather than waved through.
Removed by rebuild212

Debian OS layer — gone under Wolfi

perl, util-linux, pam, ncurses, glibc, sqlite, systemd, tar, gzip — packages a single-binary server never runs. The Wolfi rebase removes them by construction (0 OS CVEs on re-scan). Not hidden — provable by re-scanning the hardened image.
Findings by layer (as shipped)
Overall severity mix across all 233 findings:CriticalHighMediumLowUnknown
OS · Debian 13.5 · removed via Wolfi
apt / no Rust
212
app · npm dashboard · removed via API-only
build SBOM · static JS
15
app · cargo · residual (affected)
compiled into binary
6

Runtime hardening & functional parity

The hardened image must still satisfy the functional contract of the original. It does — every API path that worked before works after.
PASS
Parity gate
0
Regressions
1
Run non-root, read-only, cap-dropped
uid 10001, --read-only, --cap-drop ALL, --security-opt no-new-privileges, --memory 1g --cpus 2, telemetry off, writable paths on tmpfs.
fixes root default
2
Functional baseline (before) → parity (after)
Probed identical on original and hardened Wolfi build: GET /healthz → 200; create collection → 200 {"result":true}; upsert vectors → 200 {"status":"completed"}; vector search → 200, correct ranked result (id 1, score 0.3).
create · upsert · search all 200
3
Dashboard intentionally gone (API-only build)
GET /dashboard → 404 — expected; the UI is deliberately removed. Every API path is preserved.
expected 404
Parity gate: PASS. A production cutover should still re-run the deploying org's own test suite. Deliberately not claimed: "all remaining are unreachable" — nothing is marked not-affected on a reachability basis (see the honest caveats below).
Deep dive — the sections below are collapsed; expand what you need
▶

What still ships in the binary

The 6 residual findings are Rust crates compiled into the 82 MB qdrant binary. None are Critical, none in KEV — but they are genuinely present, and only an upstream rebuild removes them.
6 residual · 0 Critical
6 cargo findings are compiled into the binary — marked honestly affected, not not_affected. The only fix is an upstream cargo update (qdrant's job, or a source fork). All are trivial version bumps. A qdrant issue tracking these already exists (#9879).
SeverityCrateAdvisoryFix
HIGHpyo3GHSA-36hh-v3qg-5jq4→ 0.29.0
MEDIUMpyo3GHSA-chgr-c6px-7xpp→ 0.29.0
MEDIUMserde_withGHSA-7gcf-g7xr-8hxj→ 3.21.0
LOW ×3randGHSA-cq8v-f236-94qc→ 0.8.6 / 0.9.3
These live inside the compiled binary — the honest fix is an upstream rebuild with cargo update. Until then they persist through any base change, because they are the application, not the OS.
▶

npm dashboard analysis

The 15 npm findings come from the dashboard's build SBOM. Per-package triage: which are actually shipped to the browser?
1
Critical (dev)
13
Not in browser
1
Investigate
All 15 come from /qdrant/static/qdrant-web-ui.spdx.json — the dashboard is pre-compiled static JS; node_modules/vitest are not shipped as code. The API-only build (v3) removes the whole component and all 15 findings with it.
PackageSeverityNatureShipped to browser?
vitestCRITtest framework (marked DEV in SBOM)no — builds the bundle, not in it
viteHIGHbundlerno — produces the bundle
@babel/coreLOWtranspilerno — build-only
undici, form-data, ws, tar, @tootallnate/onceH M LNode-only librariesno — cannot execute in a browser
react-routerMEDbrowser routernot found in the compiled bundle
js-yamlMEDYAML parserpossibly yes (1 hit in bundle)
Conclusion: of the 15, the Critical (vitest) and all Highs are build tools or Node-only libraries — not browser-executable attack surface. Only js-yaml (Medium) is a possible genuine bundled finding. Method caveat: the bundle grep is indicative, not proof; a rigorous verdict needs the bundle's import graph.
▶

Image reputation & trust

Who publishes this image — context for how much to trust the source (as distinct from its contents).
Vendor
First-party
Popular
Vector DB
Current
Debian 13.5
Publisher
Qdrant — the first-party vendor image for the Qdrant open-source vector database. A vendor-maintained image, the norm for first-party application images.
Base freshness
Debian 13.5 (trixie) — current, not EOSL. The risk is base size, not age: a full Debian userland behind a single Rust binary.
Integrity
Scan pinned by digest, so the analysis matches exactly what runs. Exposes 6333 (REST) and 6334 (gRPC); defaults to root — the one bad default, fixed by the runtime hardening.
Provenance to still check
Vendor origin confirms the source, not a signature. cosign sign-blob / verify-blob verified working on the toolchain (Verified OK); attach an SBOM attestation if your policy requires it.
Verdict: trustworthy source. The risk in this report is about the image's base composition (a fat Debian userland + root default), not its origin. Trust the publisher; act on the findings above — pin by digest, not :latest.
▶

Key findings log

The documented findings — 4 Criticals, the 15 npm dashboard packages, and the 6 residual cargo crates. The remaining ~208 OS findings (mostly Low/Unknown Debian base packages) are removed wholesale by the Wolfi rebase and enumerated in the Trivy JSON artifact.
4
Critical
4
High
5
Medium
6
Low
Honest caveat: a scanner "0" is never zero vulnerabilities — the 6 cargo remain real even though a naive image could hide them by stripping the SBOM (which we refuse to do). Counts are relative to the Trivy DB at scan time (2026-07-08); the full 233-row scan lives in scans/qdrant/scan.json. Re-scan by digest.
IDSeverityPackageLayerStatusFixed inSummary
CVE-2026-13221CRITICALperl-baseOS · DebianRemoved (Wolfi)base swapPerl regex miscompilation — a Rust vector DB never invokes perl
CVE-2026-42496CRITICALperl-baseOS · DebianRemoved (Wolfi)base swapArchive-Tar path traversal
CVE-2026-8376CRITICALperl-baseOS · DebianRemoved (Wolfi)base swapPerl heap overflow
CVE-2026-47429CRITICALvitestnpm · dashboardRemoved (API-only)component goneVitest RCE — a test framework in the build SBOM, not shipped as executable code
GHSA (npm)HIGHvitenpm · dashboardRemoved (API-only)component goneBundler — produces the bundle, not in it
GHSA (npm)HIGHundicinpm · dashboardRemoved (API-only)component goneNode-only HTTP client — cannot execute in a browser
GHSA (npm)HIGHwsnpm · dashboardRemoved (API-only)component goneNode-only WebSocket library
GHSA (npm)MEDIUMform-datanpm · dashboardRemoved (API-only)component goneNode-only multipart library
GHSA (npm)MEDIUMreact-routernpm · dashboardRemoved (API-only)component goneBrowser router — not found in the compiled bundle
GHSA (npm)MEDIUMjs-yamlnpm · dashboardUnder investigationcomponent goneYAML parser — possibly bundled (1 hit); removed anyway in API-only build
GHSA (npm)LOWtarnpm · dashboardRemoved (API-only)component goneNode-only archive library
GHSA (npm)LOW@tootallnate/oncenpm · dashboardRemoved (API-only)component goneNode-only utility
GHSA (npm)LOW@babel/corenpm · dashboardRemoved (API-only)component goneTranspiler — build-only
GHSA-36hh-v3qg-5jq4HIGHpyo3cargo · binaryAffected0.29.0Compiled into the binary — fix by upstream cargo update
GHSA-chgr-c6px-7xppMEDIUMpyo3cargo · binaryAffected0.29.0Compiled into the binary — fix by upstream cargo update
GHSA-7gcf-g7xr-8hxjMEDIUMserde_withcargo · binaryAffected3.21.0Compiled into the binary — fix by upstream cargo update
GHSA-cq8v-f236-94qcLOWrandcargo · binaryAffected0.8.6 / 0.9.3Compiled into the binary (finding 1 of 3) — fix by upstream cargo update
GHSA-cq8v-f236-94qcLOWrandcargo · binaryAffected0.8.6 / 0.9.3Compiled into the binary (finding 2 of 3) — fix by upstream cargo update
GHSA-cq8v-f236-94qcLOWrandcargo · binaryAffected0.8.6 / 0.9.3Compiled into the binary (finding 3 of 3) — fix by upstream cargo update
Plus ~208 additional OS findings (Debian base: glibc, sqlite, systemd, tar, gzip, util-linux, pam, ncurses …) not enumerated here — all removed by the Wolfi rebase (0 OS CVEs on re-scan). Full list: scans/qdrant/scan.json.

Honest caveats

Per REPORT-SPEC §5 — the limits of this analysis, stated plainly.
This image fails the strict Alpine+Go gate. No Go call-graph reachability was produced; the Rust/npm residue is assessed by fixability + severity + EPSS/KEV + package nature, not by a proven call graph.
VEX ≠ proof. Nothing here is marked not-affected on a reachability basis. Only where the code is literally absent (component removed → provable by re-scan), or by a reasoned, disclosed argument. The 6 cargo are marked honestly affected.
"Base-slim" needs a functional test. The Wolfi rebuild was built and tested (parity PASS); a production cutover should re-run the deploying org's own suite.
Scanner "0" ≠ zero vulnerabilities. The 6 cargo remain real even though a naive image could hide them by stripping the SBOM — which we refuse to do. Counts are relative to the Trivy DB at scan time (2026-07-08).
Point-in-time. New CVEs land against the residual continuously; re-scan by digest and rebuild on a cadence.