PUBLIC-EVIDENCE AI SECURITY CASE STUDY

ChromaToast: ChromaDB Pre-Auth RCE Through Malicious Hugging Face Model Loading

HiddenLayer disclosed CVE-2026-45829 in the ChromaDB Python FastAPI server. ChromaDB marks collection creation as an authenticated operation, but an unauthenticated request can still carry embedding-function configuration that points to an attacker-controlled Hugging Face model, and request-controlled kwargs can set trust_remote_code, which tells the model loader to fetch and run Python code from that model repository. The ordering is the defect: the server instantiates the embedding function before the authentication check runs, so the model is downloaded and executed before the request is rejected. The API response may look like an ordinary error while the attacker-controlled code has already run inside the ChromaDB process, putting environment variables, API keys, mounted secrets, local data, and reachable internal services at risk. Chroma has an advisory and a remediation path, and the Rust-based deployment path is unaffected by this defect.

RAG / Retrieval-Augmented SystemTier 3Indicative ERS 4.8 (2.7–7.0)Evidence source date 2026-05-26

HiddenLayer disclosed CVE-2026-45829 in the ChromaDB Python FastAPI server. ChromaDB marks collection creation as an authenticated operation, but an unauthenticated request can still carry embedding-function configuration that points to an attacker-controlled Hugging Face model, and request-controlled kwargs can set trust_remote_code, which tells the model loader to fetch and run Python code from that model repository. The ordering is the defect: the server instantiates the embedding function before the authentication check runs, so the model is downloaded and executed before the request is rejected. The API response may look like an ordinary error while the attacker-controlled code has already run inside the ChromaDB process, putting environment variables, API keys, mounted secrets, local data, and reachable internal services at risk. Chroma has an advisory and a remediation path, and the Rust-based deployment path is unaffected by this defect.

ASSESSED SYSTEM

A network-reachable ChromaDB Python FastAPI vector-database server on a version affected by CVE-2026-45829, in its pre-fix state, serving as the retrieval and embedding layer of a RAG deployment: the collection-creation endpoint accepts request-controlled embedding-function configuration including model references and loader kwargs such as trust_remote_code, the server process can reach public Hugging Face, and the process environment carries API keys and mounted secrets. No individual victim organisation is named in the disclosure, so the assessment is of this representative vulnerable configuration rather than of one named deployment.

OUT OF SCOPE

The Rust-based ChromaDB deployment path, which the brief recommends preferring and which is not affected by this Python-server ordering defect; patched ChromaDB releases; ChromaDB as a project in its present state, since a fix and an advisory exist; the Hugging Face platform and the model-hosting ecosystem; and the RAG application logic and LLM that sit above the vector store, which are not assessed here.

Architecture: RAG / Retrieval-Augmented System (decision tree Q4) — Q1 = NO (no agents, single or plural). Q2 = NO: the server executes requests; it does not plan, hold task goals, or run a multi-step workflow of its own. Q3 = NO: the question asks whether the model calls external functions, APIs, plugins, or connectors, and here it is the database server, not a model, that reaches out — the model is the object being fetched, not the caller. Q4 = YES: the assessed system is the retrieval layer that supplies external, mutable context at inference time from a vector store, and it additionally fetches a mutable external artefact (the embedding model) from a public registry at request time. Evidence: HiddenLayer's disclosure of the collection-creation path, the request-controlled embedding-function configuration, and the AutoModel.from_pretrained() load performed by the server. Tier 3: Tier 3 (Internal): a vector database is infrastructure inside the organisational boundary supporting RAG applications, with controlled service clients rather than public users — the brief's own remediation ('restrict the ChromaDB port to trusted clients only and place it behind network policy, service authentication, and an API gateway or private service path') frames it as an internal service that should not be broadly reachable. Compromise exposes the server process, its secrets, and reachable internal services, which is organisational-boundary harm. The disclosure does not establish that the representative deployment is internet-facing, which is why this is not tiered with the confirmed-public-exposure cases.

Documented attack or failure path

  1. An attacker publishes a Hugging Face model repository containing custom loader code, or selects an existing attacker-controlled repository.
  2. The attacker sends an unauthenticated collection-creation request to a network-reachable ChromaDB Python FastAPI server, carrying embedding-function configuration that names that model and sets trust_remote_code through request-controlled kwargs.
  3. The server parses the request-controlled configuration and instantiates the embedding function before evaluating the authentication check.
  4. Instantiation resolves the model reference, downloads the repository from public Hugging Face, and — because trust_remote_code is set — executes the repository's Python code inside the long-running ChromaDB process. No artefact scanning, digest pinning, signature check, or approved-model allowlist stands in the path.
  5. The authentication check then runs and rejects the request. The caller receives what looks like an error response while the attacker's code is already executing in-process.
  6. From inside the server process the attacker code can read environment variables, API keys, and mounted secrets, access the stored vector data, and reach internal services the process can talk to; outbound egress is available for reverse shells or exfiltration unless separately restricted.

Observed controls and bounded outcomes

Positive credit is given only where the record directly demonstrates a control operating. Recommended or merely presumed controls receive no positive scoring credit.

  • Authentication was configured and did function: the request was ultimately rejected at the API layer. The defect is ordering, not absence — once the check is moved ahead of configuration loading, the same control is effective, which is why remediation is deterministic.
  • The Rust-based ChromaDB deployment path is not affected by this Python FastAPI ordering defect, so an architecturally equivalent deployment on that path did not carry the exposure.
  • Responsible disclosure and remediation worked as intended: HiddenLayer published the research with an assigned CVE (CVE-2026-45829) and a fixed release path exists, giving operators a deterministic reconciliation and patch route rather than a guardrail workaround.
  • The exposure requires network reachability to the ChromaDB port; deployments that already restricted the port to trusted clients or kept it on a private service path were not reachable by arbitrary callers, which is the same boundary that ends the attack path.

Layer 1 — Intrinsic Vulnerability Profile

Each sub-metric is placed on its five-level rubric by the evidence quoted beside it. Missing applicable evidence remains unknown. The displayed midpoint and interval are scenario values, not inferred control performance.

Sub-metricScoreRubric basisEvidence
Robustness (Ro) — scenario interval 0.00–0.80 (midpoint 0.40), Tier 3 MVT 0.40 indeterminate
Ro-4Poisoning Attack Resistance0.00w 0.200.00 — no artefact integrity validation on the model ingestion path: a poisoned source is accepted and executed without scanning, provenance checks, or quarantine.A request-controlled public model reference reached AutoModel.from_pretrained() as executable code with no integrity validation of any kind. AID-H-003.009 is listed as a Very High applicable defence precisely because the referenced repository was never statically inspected before instantiation — 'The admission scanner should reject custom-loader requirements, trust_remote_code paths, embedded scripts, dangerous serialization primitives, failed analysis, or an artifact digest that does not match the signed verdict' — and AID-H-003.006 notes that 'the exploit depends on a public model name and client-controlled loader flags reaching runtime without trustworthy artifact evidence'.source: researcher
Fairness (Fa) — scenario interval 0.00–1.00 (midpoint 0.50), Tier 3 MVT 0.45 indeterminate
Transparency (Tr) — scenario interval 0.11–0.66 (midpoint 0.39), Tier 3 MVT 0.45 indeterminate
Tr-3Audit Trail Completeness0.25w 0.250.25 — partial logging exists but omits critical fields: actor identity, the loaded model artefact and its version, and the executed side effect are all missing, so the security-relevant event cannot be reconstructed from the trail — the logged outcome is a rejection.Ordinary HTTP request logging exists in the FastAPI server, but the record actively misrepresents what happened: 'The failed API call can still compromise the server. The response may look like an error, but the attacker-controlled code has already run inside the ChromaDB process.' There is no record of the model download or of the code execution, and AID-D-004.008 (comparing the executable modules actually loaded against a signed release manifest) is listed only as an absent detective backstop. Because the caller is unauthenticated, there is also no actor identity to attach to the event.source: researcher
Tr-4Model Lineage Disclosure0.25w 0.200.25 — limited lineage artefacts exist for the model reference only; digest, signature, source attestation, loader-flag policy, and change history are absent, so tool and configuration lineage is incomplete.A model identifier and its source registry are recorded in the collection configuration, which is a minimal lineage artefact. Nothing further exists: AID-H-003.006 is listed as applicable because a model SBOM and attestation 'should record the approved model bytes, digest, source, format, tokenizer, loader commit, and flags such as trust_remote_code', none of which the assessed configuration holds. The identifier is also request-controlled rather than drawn from an approved inventory, so it evidences what was loaded but not that it was ever approved.source: brief
Privacy (Pr) — scenario interval 0.06–0.81 (midpoint 0.44), Tier 3 MVT 0.50 indeterminate
Pr-3Data Minimization Compliance0.25w 0.250.25 — some conventional handling exists (secrets supplied through environment and mounts rather than embedded in data), but the untrusted request-driven execution path is not separated from that sensitive material, so the process context retains and exposes far more than the retrieval task requires. Scored at 0.25 rather than lower because the sources describe blast radius rather than auditing the deployment's retention and logging practice.'The blast radius is the server process. Environment variables, API keys, mounted secrets, local data, and reachable internal services can all become exposed.' The remediation is to run first-use model loading 'in a short-lived sandbox with no production secrets, no shared home directory, and default-deny outbound network access' — describing a separation that did not exist. The long-running vector-database process therefore carried provider API keys and mounted secret material in the same context as a request-controlled model-loading path that had no need of them.source: brief
Containment (Cn) — scenario interval 0.00–0.48 (midpoint 0.24), Tier 3 MVT 0.50 confirmed breach
Cn-1Scope Enforcement0.00w 0.160.00 — no effective scope boundary: the system reached unauthorised code, networks, and resources at the direction of an untrusted request, with no policy denying, logging, or limiting the action.Request-controlled kwargs, including trust_remote_code, and a request-controlled model reference caused the server to fetch and execute arbitrary remote Python inside its own process, from which environment variables, API keys, mounted secrets, local data, and reachable internal services are all in scope. Nothing constrained which model references or loader flags a request could supply; the recommended control is to 'Block request-controlled model names, kwargs, and trust_remote_code from production collection-creation paths' and offer 'an allowlist of approved internal model identifiers instead of raw public model references'.source: researcher
Cn-2Escalation Prevention0.00w 0.160.00 — no escalation controls on the exploited path: an unprivileged, unauthenticated caller obtained the server's privileges and bypassed the approval workflow that nominally governed the operation.An unauthenticated external caller obtained arbitrary code execution in the server's process context, with the process's full privileges and access to its secrets. No privilege boundary separated request parsing from model instantiation: 'The Python server instantiates the embedding function before the authentication check, so the model is downloaded and executed before the request is rejected.' The authorisation workflow that was supposed to govern collection creation was bypassed entirely by the ordering, not defeated.source: researcher
Cn-5Agent Identity Integrity0.00w 0.110.00 — the rubric's bottom anchor is satisfied literally on the exploited path: the service accepted and acted on an unauthenticated call, with no binding between caller identity and the privileged invocation. The presence of a late-running authentication check is recorded as a control that partially held but does not lift the score, because it did not gate the operation that mattered.'ChromaDB marks collection creation as authenticated, but an unauthenticated request can still carry embedding-function configuration that points to an attacker-controlled Hugging Face model.' The server acted on an unauthenticated call. Authentication existed and did eventually reject the request — the defect is ordering, not absence — but it was not a precondition of the privileged operation, so caller identity had no bearing on whether code executed. AID-H-004.002 is listed as the clearest break point: 'Verify the caller identity before any request-controlled model configuration is parsed, fetched, instantiated, or executed.'source: researcher
Cn-6Action Reversibility Classification Rate0.00w 0.090.00 — no reversibility classification is performed before execution; the model-instantiation action, whose effect is irreversible in-process code execution, runs ungated (ARCR = 0).The brief's central lesson is that model loading is code execution, and the assessed configuration performed that load — an action that cannot be undone once foreign code runs in a long-lived process — with no pre-execution classification and no gate. The recommended controls are exactly the missing gate: block request-controlled loader flags from production paths, route approved models through a registry with scanning, signatures, digest pinning, and loader-policy checks, and 'Run first-use model loading in a short-lived sandbox'. None of these classified or restricted the action before it executed.source: brief

Unknown, not N/A: 15 applicable sub-metrics lack admissible public evidence. The lower, midpoint, and upper scenarios evaluate each at 0.00, 0.50, and 1.00 respectively; no weight is redistributed merely because evidence is missing.

Layer 2 — Operational Risk Posture

DimensionScoreJustification
AaAutonomy Amplification0.50w 0.20A vector database is not a decision-making agent: it does not plan, choose goals, or act outside the scope of an inbound request, which rules out the 0.75 and 1.00 anchors. It is well above the 0.00 and 0.25 anchors because it holds write authority over its own state and, critically, executes a consequential autonomous action as a side effect of a request — resolving, downloading, and instantiating a remote model artefact — with no confirmation step. That is the 0.50 anchor: routine actions executed autonomously within what were intended to be pre-defined boundaries.
AsAttack Surface Exposure0.90w 0.25Documented intermediate above the 0.75 anchor. The assessed configuration accepts requests from any network-reachable caller with no authentication gating the dangerous path, and the artefact it ingests is not merely partially trusted external data but fully attacker-supplied executable code fetched from a public registry at request time — which is the substance of the 1.00 anchor's untrusted-external-ingestion condition. It is held just below 1.00 because internet reachability is not established for every deployment in the class; the brief's guidance to restrict the port to trusted clients implies that broad reachability is common but not universal. elevated
CpCascade Potential1.00w 0.30No System Dependency Graph is published for any affected deployment, which alone forces the worst-case default; the reconstruction also triggers the 1.00 anchor independently. An ungated path runs from an unauthenticated request to arbitrary code execution inside the vector-database process, reaching a credential-bearing node — 'Environment variables, API keys, mounted secrets' — and from there 'reachable internal services'. Stolen provider keys and mounted credentials let the attacker act as the service elsewhere, so the path terminates at credential-issuing capability with no gate anywhere along it, and the taint traverses the model layer, the store's own state, and downstream internal systems from a single origin.GDCP: corroborated by the observed path elevated
RfRemediation Feasibility0.00w 0.25The 0.00 anchor applies squarely: a deterministic software fix exists. The defect is an ordering bug in a specific code path, CVE-2026-45829 is assigned with an advisory, patched releases and an unaffected Rust deployment path are available, and the compensating controls are ordinary configuration changes — move authentication ahead of configuration loading, block request-controlled model names and loader kwargs, restrict the port. AID-H-003.010 frames remediation as reconciling deployed versions against the advisory and verifying no vulnerable digest remains, which is patch management, not model work.

Nelevated = 2 (dimensions strictly above 0.75) → CRM = 1.15.

Compound Risk Alert. Two or more dimensions are simultaneously elevated (spec 3.2.2); architectural decomposition is recommended before deployment.

Layer 3 — Public-evidence confidence diagnostic

ComponentScoreBasis
Pc — Public provenance evidence0.20Documented intermediate below the 0.25 anchor. The software component, its vendor, the affected deployment path, and the precise vulnerable code ordering are all documented and carry a CVE identifier, which is strong provenance for the component. But no assessed deployment has an owner of record, and there is no model or artefact provenance at all — the embedding model is chosen by the request, so there is nothing approved to trace — and no tool inventory, identity policy, or change record exists. The 0.25 anchor requires a documented deployment owner and a high-level tool inventory, neither of which is available.
Ec — Public evaluation coverage0.33coverage 0.35 (8 of 23 applicable sub-metrics) × independence 1.00 × fidelity 0.95. No Full, Standard, or Lite pathway is claimed for a retrospective article.
Tf — Public-evidence freshness0.35Evidence dated 2026-05-18; age 87 days on the workpaper reference date. Components: C_event 0.35 · C_monitor 0.65 · T_calendar 0.72 · C_evidence 0.85. Binding term: C_event. dt_days = 87, measured from the primary public disclosure dated 2026-05-18 to the 2026-08-13 evidence reference date; the AIDEFEND brief republished the analysis on 2026-05-26. agentic = false because the architecture class is RAG, not an Agentic/Multi-Agent/Tool-Calling class, so the containment staleness floor is not applied. The counter-argument is recorded for the reader: this configuration does have a runtime-mutable permission boundary in the spec's sense, because the embedding-function 'tool' is reprovisioned from a caller-supplied reference on every request, which is exactly the condition M_Cn targets; the class-based rule is followed for cross-case consistency, and the choice is immaterial to the result because C_event binds Tf well below either decay term. baw = false: the assessed component is a retrieval store, and the sources do not establish model- or agent-written memory in the affected deployments; the exploited path is a configuration and loading defect rather than behavioural state, so the BAW checklist is not met. C_monitor = 0.65: a genuine detection failure — the deployment's telemetry records a rejected request while attacker code executes, and runtime module-loading integrity monitoring (AID-D-004.008) is listed only as an absent backstop. C_event = 0.35: a major event — the assessed state is the pre-remediation configuration of a confirmed, publicly demonstrated pre-authentication remote code execution defect, which is a compromise-class condition for every deployment on an affected version. C_evidence = 0.85: unresolved artefact-provenance and tool gaps — no model SBOM, no digest pinning, no loader-flag policy, and request-controlled model references remain in the assessed configuration. Public-evidence coverage is reported directly; no AITBM assessment pathway is assigned.

Public-evidence ACI = (Pc × Ec × Tf)1/3 = 0.28 — diagnostic status: Invalid as assessment-of-record evidence. It describes the evidence available to this case study, not the assurance of the underlying system, and is not inserted into the normalized-assurance scenario ERS.

Indicative ERS — normalized-assurance scenario

Worp · ORP0.20(0.50) + 0.25(0.90) + 0.30(1.00) + 0.25(0.00) = 0.625
CRMNelevated = 2 → 1.15
ORPeffective0.625 × 1.15 = 0.719
Wivp · IVP midpoint0.20(0.40) + 0.15(0.50) + 0.20(0.39) + 0.25(0.44) + 0.20(0.24) = 0.390
IVP mitigation0.15 + 0.85(1 − 0.390) = 0.669
Scenario assuranceACI fixed at 1.000 for cross-case comparison; public-evidence ACI 0.285 is diagnostic only
Indicative ERS midpointmin(10, 0.719 × 0.669 × 1/1.000 × 10) = 4.8
Unknown-input interval2.7–7.0; 15 unknown applicable sub-metrics set to 1.00 / 0.00 at the bounds

AIDEFEND defences → AITBM sub-metrics

Identifiers are quoted as they appear on the AIDEFEND in Action brief (retrieved 2026-08-13); the sub-metric mapping is AITBM's own, from the specification's AIDEFEND tables reconciled at catalogue data version 2026.08.05. AIDEFEND renumbers identifiers between releases, so the data version travels with every mapping and neither side's IDs should be cited without one. A mapping identifies a possible evidence route; a recommendation does not prove that the control was implemented or effective and receives no scoring credit by itself.

TechniqueDefence PriorityEvidences
AID-H-004.002Service & API AuthenticationParent AID-H-004 (Identity, Access & Trusted Communication for AI Systems), catalogue dataVersion 2026.08.05. Both arms are exercised: verifying the caller before any request-controlled configuration is parsed is the Cn-5 = 0.00 finding, and the absence of an authenticated actor on the executed event is part of Tr-3 = 0.25.Very HighCn-5 Tr-3
AID-H-003.009Model Artifact Static Malware & Unsafe-Serialization ScanningParent AID-H-003 (Secure ML Supply Chain Management), dataVersion 2026.08.05. The primary admission control whose absence sets Ro-4 = 0.00; rejecting trust_remote_code paths and custom-loader requirements is what would have stopped the request-controlled model reaching AutoModel.from_pretrained() as executable code.Very HighRo-4 Tr-4
AID-H-003.006Model SBOM & Provenance AttestationParent AID-H-003, dataVersion 2026.08.05. The missing digest-bound provenance record — approved bytes, digest, source, format, tokenizer, loader commit, and loader flags — is the direct basis for Tr-4 = 0.25.HighRo-4 Tr-4
AID-H-003.010Deployed AI Software Vulnerability Remediation LifecycleParent AID-H-003, dataVersion 2026.08.05. Owns reconciliation of deployed ChromaDB versions against the advisory; its existence as a clean, deterministic remediation route is the evidence behind Rf = 0.00.HighRo-4 Tr-4
AID-I-001.002MicroVM & Low-Level SandboxingParent AID-I-001 (AI Execution Sandboxing & Runtime Isolation), dataVersion 2026.08.05. The catalogue maps this parent to Pr-2 (inference attack resistance), which this incident does not exercise — no inference attack occurred. Its actual relevance here is first-use model-load isolation, which speaks to Cn-1 and Pr-3; no Pr-2 score is asserted.HighCn-7 Pr-2
AID-I-001.004Sandbox Network Egress RestrictionsParent AID-I-001, dataVersion 2026.08.05. Same caveat as AID-I-001.002: the catalogue's Pr-2 arm is not exercised. Default-deny egress here is post-execution blast-radius containment against reverse shells and credential exfiltration, which is Cn-1 and Pr-3 territory; no Pr-2 score is asserted.HighCn-7 Pr-2
AID-D-004.008AI Runtime Code and Module Loading Integrity MonitoringParent AID-D-004 (AI Artifact, Runtime Configuration, Route & Lifecycle Integrity Monitoring), dataVersion 2026.08.05. Both arms are exercised. Its absence is the main basis for C_monitor = 0.65: it is the only listed control that would have observed the unapproved model loader entering the process while the API returned an error.MediumCn-7 Ro-4 Tr-3

WHAT THIS CASE TEACHES

Remediation Feasibility sits at its bottom anchor — a patchable ordering bug with a CVE and a fixed release — while Cascade Potential still forces 1.00, which is exactly the layer separation AITBM is built for: how easily a defect is fixed and how far it reaches are scored independently, so a cleanly patchable flaw never gets to look harmless.

Sources: Primary source — ChromaToast Served Pre-Auth (2026-05-18) · AIDEFEND in Action — ChromaToast: ChromaDB Pre-Auth RCE Through Malicious Hugging Face Model Loading

AITBM sub-metrics referenced