Six Runtimes, One Pattern: The 2026 CVE Wave Across the Self-Hosted AI Inference Stack

Six runtime families, one pattern: the same five architectural flaws across Ollama, llama.cpp, vLLM, NVIDIA Triton, MLflow, and MCP — an evergreen operator deep-dive of the 2026 CVE wave, with per-flaw detection commands and a durable 12-item checklist.

Share

Date: 2026-09-01 | Type: Pattern analysis (evergreen) | Scope: Six runtime families: Ollama, llama.cpp, vLLM, NVIDIA Triton, MLflow, MCP tool layer. 18 CVEs, 2024-2026 | Environment: Malwlab homelab (self-hosted AI inference stack)

TL;DR

In the space of about eighteen months, six different runtime families that people run in their own racks all got broken in the same handful of ways. Not the same bug. The same shape of decision. One unauthenticated listener on 0.0.0.0 that hands its session to whoever shows up. One parser that treats a downloaded model file as authoritative without checking it. One outbound "test webhook" that will happily fetch an internal metadata address and reflect the answer back. One operator token that every caller on the network gets to reuse because the transport never asked who is dialing in. One "pinned revision" that quietly resolves sibling artifacts from somewhere else.

None of these are exotic. They are the defaults. And that is the point: the CVE numbers rotate, the runtimes ship and get replaced, but the five flaws below keep reappearing in the next runtime because nothing in the deployment process forces a team to argue against each one. If you run any of this at home (a single llama-server, an Ollama box, a vLLM endpoint, a Triton sidecar, an MLflow tracker, or an MCP server with a token in its environment), this is the threat model that actually matches your hardware.

This is not a per-runtime changelog. It is the pattern underneath all six, with a detection command for each flaw and a checklist that should still be true in two years. The single-deployment threat model is covered elsewhere; the multi-tenant vLLM internals are covered elsewhere. Here is the cross-cutting structural argument, with the Malwlab rack as the worked example.

The open: a quiet Tuesday in the lab

The reason this is a wave and not a bug list became clear to me the afternoon the scanner finished its Tuesday sweep and I opened the results on the rack. I was not looking for a headline. I was running the same read-only port and bind audit I run every couple of weeks (ss -tlnp, a sweep of /proc/*/cmdline for stray tokens, a check of which runtimes were still bound wide), and the output was not one red flag. It was six of them, in six different processes, all saying the same thing in different languages: this listener is reachable, and nobody asked who you were.

That is the frame I want to put on this piece before the CVE numbers. I did not have a single vulnerable thing in the lab. I had a stack, and the stack was doing the same five things wrong at once, distributed across components I had each installed for a legitimate reason. An Ollama box bound to the LAN. A llama-server serving a GGUF I had pulled from a mirror. A vLLM endpoint in a container. An MCP server I had stood up to talk to a Git forge, with the forge's API token sitting in its environment. The components did not know about each other. But the flaws did. They were the same five flaws, and they compounded.

So I am going to walk the five flaws in the order that matters to an operator at the keyboard, not the order NVD published them. For each one: what the flaw is, the cleanest CVE in each runtime family that manifests it, and (the part that makes this evergreen) why the next runtime to ship will hit it again unless somebody explicitly decides otherwise. Then the detection commands, then the checklist, then the Malwlab rack mapped against all five.

A note on sourcing, because this is a piece operators will copy-paste from. Every CVE identifier, CVSS score, fix version, and KEV status below is taken from the primary records (NVD, the vendor GHSA, the NVIDIA product-security bulletins, and the CISA KEV JSON feed) and cross-checked in the verification pass that preceded this draft. Where the sources disagree (and they do, in three places), I say so inline and cite both sides rather than smoothing it over. The full reference list is at the end, and the inline numbers point into it.

The five shared flaws

Before the five, one framing that holds all of them together. A self-hosted AI inference stack is a small cluster of untrusted-input processors that an operator has, by and large, decided to run without the trust boundary the input actually needs. A model file is untrusted input. A URL in a webhook config is untrusted input. A request to an MCP endpoint from an unknown source is untrusted input. The runtimes were each written to make the single-operator, single-machine case fast, and they did it by assuming the boundary the operator holds in their head ("this machine is mine, local traffic is safe, I am the only one dialing in") is also a boundary the software enforces. It is not. It is a wish. Every flaw below is that wish failing in one specific place.

Flaw 1: the unauthenticated 0.0.0.0 bind, and the operator token that sits next to it

This is the one the scanner found first, and the one every homelab operator has, in some form, at least once. A service listens on every network interface, and either accepts traffic without asking for any credential at all, or it holds an operator-grade token that is sitting in a process environment, a systemd unit, or a docker-compose.yml .env file, readable by anyone with process-level access to the box. The operator trusts the local boundary. The runtime does not enforce it, and on a flat LAN the local boundary is not where the operator thinks it is.

The cleanest canonical example in this wave is argocd-mcp 0.8.0, an MCP server for Argo CD. The vendor advisory is unusually blunt about the shape: "argocd-mcp 0.8.0 starts its HTTP transport on every network interface. When ARGOCD_API_TOKEN is configured, a network caller can create an MCP session without presenting any inbound credential. The server then executes its tool surface with the stored Argo CD token." [40] The advisory goes on to note the HTTP app "has no Origin or Host validation" and that the listener starts with a bare app.listen(port) (i.e. every interface, no inbound identity) [40]. The recorded vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H, a 10.0, with CWE-1327 (Binding to an Unrestricted IP Address) and CWE-306 (Missing Authentication for Critical Function) [40][46]. Two things about that 10.0 matter for this piece. The scope change (S:C) is there precisely because the failure crosses from the exposed Node process into the operator's Argo CD account and, from there, into the destination Kubernetes cluster [40]. And the CWE pair is the whole flaw in two acronyms: bind-wide, no inbound auth.

Now spread the same shape across the families. nginx-ui is the "no auth at all" extreme: its /mcp_message endpoint, per the advisory, "only applies IP whitelisting - and the default IP whitelist is empty, which the middleware treats as 'allow all'," so "any network attacker can invoke all MCP tools without authentication" [31]. That is CVE-2026-33032, "MCPwn," CVSS 9.8 [14][31]. Note the version conflict, and it matters if you are trying to patch: the official GHSA says affected versions are "2.3.5 and prior" with no publicly available patch at publication [14][31], while the finder's own report claims a fix landed in 2.3.4. I am citing the official position (no published patch) and leaving the 2.3.4 claim as the finder's, because a patch you cannot find on the vendor page is not a patch you can rely on.

On the inference-engine side, the same bind flaw hides in a library nobody thinks of as a server: vLLM's KV-cache transfer path. PyTorch's TCPStore, the coordination primitive vLLM uses to move data between its worker processes, "listens on ALL interfaces, regardless of what IP address is provided," and the fix for the deserialization issue in that same channel was to "force the TCPStore instance to bind its socket to a specified private interface" [5][22]. The point for the pattern: the unauthenticated bind is not always on a port you chose to open. Sometimes it is inside a library the runtime drags in for an internal job, and it binds wide by default regardless of what you passed it.

Ollama's Probllama (CVE-2024-37032) is the older member of the same family, and it is worth keeping in because it is the one most readers will recognize. NVD's description: the Ollama API server was reachable with low privileges, and a path traversal in the model-name path turned a low-privilege request into code execution. The vector is CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (an 8.8), and the PR:L is the tell. This is not "totally anonymous"; it is "anyone with a low-privilege foothold on the network," which on a home LAN is essentially anyone on the LAN [1][18]. The fix was in 0.1.34 (affected < 0.1.34, patched 0.1.34), from PR #4175 [1][18]. I am pinning the fix to 0.1.34 on purpose, because the "0.1.46" number that circulates for Ollama belongs to a different, later July-2024 cluster (CVE-2024-39720/39721/39722) and must not be merged with Probllama.

The serving-engine member of this family is NVIDIA Triton Inference Server, CVE-2026-24207, an authentication bypass leading to code execution. NVIDIA records it at 9.8, vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, affecting all versions prior to r26.03 [9][26][38]. An auth bypass in a model-serving endpoint is the same decision as the wide bind, in that the trust boundary that was supposed to be enforced was not, except the consequence on a GPU box is code execution rather than a stolen model. (Triton also carried two resource-exhaustion denial-of-service issues in this window, CVE-2026-47628 and CVE-2026-24215, fixed in 26.06 and r26.03 respectively [10][12][27][29][39]. Those are availability-class, not data-integrity, so they fall outside the five flaws below, but I am citing them here so the runtime's full wave is not silently dropped from the count.)

Why this recurs, and why the next runtime hits it: the self-hosted mental model is "local is safe," and the ML stack is built from components whose default is the opposite. A Python web framework defaults to 0.0.0.0. An RPC backend binds wherever the OS lets it. A config file holds the operator token in plaintext next to the very service that uses it, because the operator needs the token in the environment to make the service work in the first place. Every new runtime inherits this shape until somebody writes explicit binding rules, and most teams never do, because the local case works and the wide case is the one they have not been hurt by yet. The flaw is not that one team made a mistake. It is that the default, across the whole ecosystem, is wide-open, and the onus to close it falls on every operator individually.

Flaw 2: untrusted input into a deserializer, or a model-file parser

If Flaw 1 is "you let the caller in," Flaw 2 is "you let the file in." A parser accepts a file the user supplied (a model weight, a config, a serialized checkpoint) and runs it through pickle, unmarshal, an integer-overflow-prone binary decoder, or an HTTP-body unserializer, without validating size, structure, signature, or source. The attacker does not need inbound access to the service at all. They only need to get a file to a place the runtime will load: a HuggingFace mirror, a docker volume, a download path, a model registry. The model is the payload, and the parser is the interpreter. I have written a separate piece on the GGUF format as an attack surface; this section is the class of bug across runtimes, not the format forensics.

The canonical example in this wave is vLLM CVE-2025-47277, which is a good one to lead with because it is a textbook CWE-502 (deserialization of untrusted data) with a 9.8. The KV-cache channel exposed a CPU-side object channel (send_obj / recv_obj) whose backing TCPStore was bound to all interfaces, so an unauthenticated peer on the network could drive the deserialization of arbitrary object payloads into a running engine [5][22]. The advisory is precise about the fix: the channel "was fixed to use a workaround to force the TCPStore instance to bind its socket to a specified private interface" [22]. One wording note for accuracy: the press shorthand for this is "pickle RCE," but it is technically object deserialization over TCPStore, not vLLM's main request path. The pickle label is a loose metonym, and the CWE is 502, not 94 [22].

The model-file analogue is llama.cpp, and it is the one that most directly touches a home rack, because a home rack loads GGUFs. This is the correction the verification pass forced, so read it carefully: the CVE that was originally slotted under Ollama in the brief is actually a llama.cpp CVE. CVE-2026-27940: NVD's own text, quoted because it is the cleanest statement of the bug, reads: "llama.cpp is an inference of several LLM models in C/C++. Prior to b8146, the gguf_init_from_file_impl() in gguf.cpp is vulnerable to an Integer overflow, leading to an undersized heap allocation. Using the subsequent fread() writes 528+ bytes of attacker-controlled data past the buffer boundary. This is a bypass of a similar bug in the same file - CVE-2025-53630, but the fix overlooked some areas. This vulnerability is fixed in b8146." [2] The vector is CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H, a 7.8, local attack vector with user interaction [2]. The AV:L and UI:R matter: this is not something the internet does to you passively. It is what happens when you, or a process you trust, load a file you should not have. And the phrase "the fix overlooked some areas" is the whole evergreen argument in one line, because the bypass it describes (CVE-2025-53630, an integer overflow in the same function gguf_init_from_file_impl() [8][25]) shows that patching one site in an integer-overflow-prone decoder does not patch the class. You find the class only when the next overflow lands in the area the last fix skipped.

Then there is CVE-2026-34159, also llama.cpp, and this one is the sharper of the two: 9.8, AV:N/AC:L/PR:N/UI:N, network-reachable, no privileges, no user interaction [7]. The GHSA: deserialize_tensor() "skips all bounds validation when a tensor's buffer field is 0," reachable through the RPC backend, giving unauthenticated RCE via a crafted GRAPH_COMPUTE payload [24]. NVD records it "patched in version b8492" [7]. So the same parser family, two different entry points: the file-on-disk overflow (27940, 7.8, local) and the network deserialization (34159, 9.8, remote). A home operator reading only the 7.8 and concluding "llama.cpp is fine, it needs a local file" would be missing the 9.8 that needs only a network peer and a crafted payload.

The same class shows up in vLLM's model-loading path as an assert-based check bypass: CVE-2026-41523. In optimized mode, an activation function loaded from a HuggingFace model drives arbitrary code execution because the guard that was supposed to reject it was an assert, and asserts do not run in optimized builds. The vector is 7.5, AV:N/AC:H/PR:N/UI:R [3][20]. The fix was in 0.22.0 [3]. The pattern here is subtler than a missing check: the check existed, it was just written as a debug assertion and silently disabled in exactly the mode operators run in production. "Assert is not a security boundary" is a rule that keeps being relearned, in each runtime, one optimized build at a time.

And Ollama's Probllama reappears in this flaw, because the path traversal was really an unvalidated-digest bug wearing a traversal costume: the server accepted a SHA-256 digest it did not validate the format of, and a crafted digest let a model file get loaded as a filesystem path, so an unvalidated input shaped a control-flow decision the parser never sanitized [1][18]. The two Ollama CVEs (the bind/traversal of Flaw 1 and the digest of Flaw 2) are the same root decision seen from two sides: the model file is treated as trusted.

The same "untrusted file shapes control flow" pattern lands in NVIDIA Triton Inference Server, CVE-2026-24147: a model-config upload path that is vulnerable to path traversal (CWE-22), leading to information disclosure. NVIDIA records it at 4.8, vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L, affecting all versions prior to r26.02 [11][28][37]. The severity is lower than the RCE entries in this flaw because the consequence is disclosure, not execution, but the structural decision is identical: a file path the runtime builds from an operator-supplied value is resolved without validating that it stays inside the directory the operator meant, so an untrusted input reaches a filesystem location it should not. The GGUF parser is the model-file version of this; Triton's config upload is the config-file version. Same flaw, two file types.

Why this recurs: the "the model is user data" principle has no enforcement boundary anywhere in the current tooling. GGUF, SAFETENSORS, and pickle are all, by construction, untrusted when they come from a third party, and the operator downloads from mirrors and repos and the runtime treats the file as the authoritative source of truth for weights, config, and tokenization state. Every new inference format ships with a parser that trusts its own input until proven wrong. The llama.cpp bypass chain (53630 → 27940) is the proof that "proven wrong" is a moving target: the fix for one overflow in a decoder is a point fix in a file full of the same arithmetic, and the next overflow is in the area the fix did not look at. Until a parser validates structure and source and signature before it deserializes, the class stays open, and each runtime that adds a new model format re-opens it with a fresh decoder nobody has overflowed yet.

Flaw 3: SSRF to internal and cloud metadata from an unvalidated fetch path

A runtime makes an outbound HTTP request on the operator's behalf (a webhook test, a registry check, a model download), but the URL it fetches is influenced by data the operator did not fully control, and it follows redirects without re-validating the target. The classic victim is the cloud metadata service at 169.254.169.254. Reach it once from a service running on a VPS or in a VPC, and you have a credential-leak primitive that needs no inbound access to the runtime at all. The operator thought they were testing a webhook. The runtime was fetching IMDS.

I am keeping this section to one canonical example by design, because the deep coverage belongs to the dedicated MLflow draft in this pillar. The point here is the class, and the cleanest member of the class is the one with the loudest confirmation: MLflow CVE-2026-64849.

The advisory describes an unauthenticated POST /api/2.0/mlflow/webhooks/{id}/test endpoint that "returns the upstream response status and body to the caller." The guard, in the advisory's words, "validates but pins nothing": delivery "follows HTTP redirects (no allow_redirects=False) and never pins the validated IP," so "MLflow follows it and never re-validates the redirect target. Because /test reflects the response body, this is an unauthenticated full-read SSRF on a default server" [30]. NVD confirms the target class: the flaw "allow[s] attackers to reach internal or cloud metadata services and receive response_status and response_body" [13]. The recorded vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N, a 9.3 with a scope change, CWE-918 [13].

And this is the one CVE in the whole wave that is not merely disclosed; it is confirmed exploited. CISA added CVE-2026-64849 to the Known Exploited Vulnerabilities catalog on 2026-08-19, with a federal remediation due date of 2026-09-02 [35][36]. In a wave of eighteen CVEs, this is the only one on KEV as of the 2026.08.31 catalog snapshot [36]. The fix is a DNS-rebinding-SSRF fix in webhook delivery, commit ba94952, shipped in 3.15.0 [42][43][44].

That single KEV row is the whole argument for this section, and I am deliberately not spending the section's budget on it. The dedicated MLflow draft covers the mechanism, the PoC shape, and the patching in depth. What I want here is the operator takeaway: every outbound fetch a runtime makes on user-influenced input is an SSRF primitive the moment it can be pointed at a link-local metadata address. The MLflow case is the confirmation that this is not theoretical. The Azure MCP Server case below is the confirmation that it is not even limited to tracking servers.

Azure MCP Server CVE-2026-26118 is the same class with one required credential. NVD: "SSRF in Azure MCP Server allows an authorized attacker to elevate privileges over a network," vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, 8.8, CWE-918 [50]. The fix is across three package families per the GHSA: Azure.Mcp (NuGet) and @azure/mcp (npm) below 1.0.2 and below 2.0.0-beta.17, and msmcp-azure (pip) 2.0.0b14 through 2.0.0b16 fixed in 2.0.0b17 [51]. Two honest caveats I am carrying rather than smoothing. First, the task's original framing said "IMDS token theft," but the verified scope in the NVD and GHSA records is "SSRF ... elevates privileges over a network". The specific IMDS mechanism was not confirmable from the vendor page, which is a JavaScript app with no machine-readable endpoint, so I am stating the verified scope and not asserting the IMDS detail as fact [50][51]. Second, the fix versions come from the GHSA package table, not a single release page, so if you run one of the three package forms, check the specific one you use [51].

Why this recurs: webhook, test, and verification endpoints are designed for operator convenience: "click the button, see if it reaches your target." The security story is an afterthought, because in the single-operator case the operator is the only one with a URL to test. But the moment the URL comes from a database, a config file, or a request body instead of the operator's keyboard, the fetch is no longer the operator's action; it is an attacker's cursor into your internal network. Cloud vendors have responded by routing IMDS through link-local sinkholes and IMDSv2 (which requires a session token), which shrinks the classic metadata-theft path, but the structural fact remains: any service that can reach 169.254.169.254 and will fetch a URL it did not itself author exposes its credentials to whatever code it runs. New runtimes keep adding "test this connection" buttons and model-registry lookups, each one a fresh unvalidated fetch, and the fix surface is the same every time: pin the resolved IP, never follow a redirect without re-validating the target, and refuse link-local and metadata ranges outright.

Flaw 4: token and credential reuse in MCP, where the transport has no session auth

This is the flaw that is newest to the stack and the one most likely to be in a homelab by now, because MCP is the glue people are bolting onto everything. The MCP pattern is a server with a set of tools, invoked by sessions, where the sessions all share the same backend credential. If any caller can create a session without proving identity, the authentication collapses: one operator token, many unauthenticated callers, each one exercising the full tool surface as the operator. There is no per-session identity. The transport says nothing about who is dialing in, so the server assumes it is the operator, and executes.

argocd-mcp is canonical here, and I am using it in this flaw as well as Flaw 1, because it manifests both flaws, and the distinction is the lesson. In Flaw 1 the problem was the wide bind. In Flaw 4 the problem is that the credential model itself is one-token-for-everyone. The server "executes its tool surface with the stored Argo CD token" for any session, because the HTTP transport carries no per-session authentication [40]. The advisory's suggested fix is exactly the missing piece: "Require a separate inbound credential for network transports. ARGOCD_API_TOKEN and registry tokens must remain outbound credentials and must never authenticate an inbound caller" [40]. That sentence is the entire mitigation for this flaw, stated by the reporter.

The 10.0 score's scope change is doing the same work as a footnote: it is high partly because the operator token is reused across untrusted callers, so the compromise does not stop at the MCP process [17][40].

nginx-ui is the degenerate case: there is not even a token to reuse. "Any network attacker can invoke all MCP tools without authentication" [31]. If Flaw 4 is "one token, many callers," nginx-ui is "no token, any caller." It is the same architectural assumption (the transport does not identify the caller) taken to its logical end.

Azure MCP Server shows the reuse path even where some auth exists. An authorized caller's request is used server-side to reach internal endpoints and elevate privileges [50][51]. The lesson: adding authentication to the inbound call is necessary but not sufficient. If the server then turns around and uses the caller's context to make privileged server-side calls to other endpoints, the auth on the front door does not bound what happens behind it. Reuse is the flaw, and reuse has two faces: no inbound auth at all, or inbound auth that the server silently escalates.

Why this recurs, and why it is the flaw I would spend the most time on in a new stack: the MCP architecture is designed around single-operator trust. A server that talks to your Git forge, your GitOps tool, your cloud, your database, is written for the person who set it up, and the credential it holds is that person's credential. That is correct for one operator on one machine. The moment you expose that surface to a network, which homelab and small-team deployments do routinely for "convenience", the lack of per-session identity means every session is, as far as the server can tell, the same session: the operator's. There is no built-in mechanism in the current MCP transports for a server to say "this caller is Alice, and Alice's tool set is different from Bob's." They inherit whatever auth the underlying HTTP transport provides, and most of those transports provide none on the inbound path. Every new MCP server that ships will have the same problem until the ecosystem adds per-session identity to the transport, and until then the operator's only defense is the one stated in the argocd-mcp fix: never let the outbound token double as the inbound credential, and enforce a separate per-request bearer check at the proxy in front of the server.

Flaw 5: artifact-boundary isolation failure in multi-user serving

I want to be precise about what this flaw is and is not, because the verification pass corrected the framing, and getting it right matters for a piece operators will act on. The brief originally described this as "tenant isolation" at the user or session level, one user's request leaking another user's session data. I could not find that claim in any primary source. What is documented, from the primary evidence, is an isolation failure at the model-artifact boundary: a deployment that believes it is serving one pinned, reviewed revision can still resolve behavior-affecting artifacts from somewhere else. That is a real and serious failure, but it is not cross-user session data exposure, and I am not going to present it as one.

The documented case is vLLM CVE-2026-47155, which the advisory calls "Artifact Pin Decay." NVD's description: a deployment "that supplies --revision or --code-revision can still load dynamic code, GGUF files, image processors, retrieval side weights, or same-repository subfolder weights/config from an unpinned/default revision," so "[o]perators can believe they are serving a reviewed model revision while vLLM resolves behavior-affecting nested or sibling artifacts outside that reviewed revision" [4]. The vector is CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N, a 6.5 MEDIUM, CWE-345 (Insufficient Verification of Data Authenticity) [4]. The fix was in 0.22.0 [4].

I am stating the 6.5 explicitly and not the higher number, because the brief's "server takeover by unauth user, CVSS 8.8" label does not match this CVE in any primary source I checked. That higher-severity framing belongs to CVE-2026-22778, the vLLM multimodal RCE chain, which is 9.8 CRITICAL [6][23]. These are two different bugs and I will not blur them: 47155 is a pin-integrity failure that lets unreviewed code and weights load alongside a "pinned" model, and 22778 is a heap-address leak through a multimodal error path chained with a decoder overflow to full RCE. Both are vLLM, both are in the wave, and both matter, but they answer different questions. 47155 answers "is my pinned model actually the model I think it is." 22778 answers "can an unauthenticated caller with a malformed image get code execution." I am covering 47155 here, in this flaw, because it is the artifact-isolation bug. The 22778 multimodal chain is a deserialization/parse bug that also belongs in the Flaw 2 family, and I am referencing it there rather than re-deriving it.

Now, the honest scope of this flaw for a home operator: it is dormant on a single-operator setup. Artifact-boundary isolation failure requires a second party whose artifacts can bleed into yours, or a supply chain that resolves artifacts you did not pin. If you are the only person routing models through your stack, there is no second tenant whose sibling weights could contaminate your loaded revision, and the exploitation path is narrow. It becomes live in three situations: (a) you serve multiple users or multiple teams through one engine, so a "pinned" model can pull sibling artifacts a different user influenced; (b) you load from a shared model registry where the repository layout means "pinned revision" and "pinned model" are not the same thing; or (c) you vendor a runtime and do not control the artifact-resolution path at all. If none of those apply to you, this flaw is a monitoring item, not a tonight item, and that is a legitimate conclusion, not a cop-out.

Why this recurs: multi-tenant serving in ML infrastructure defaults to "trust all callers and all artifacts on one host," because the deployments that need it are teams of five to fifty on a single rack, and the isolation the operator wants (per-user artifact roots, signature verification at load time, a pinned-revision model root) is non-trivial to implement and, more importantly, not the default in any of the runtimes in this wave. Per-call path rewriting, load-time signature checks, and revision-pinned model roots are all things a runtime could do and currently does not do by default. The fix surface touches the model-loading code path in every runtime that supports dynamic weights or revision pinning, which is to say it touches the most performance-sensitive part of the stack, and the teams that own that code are optimizing for throughput, not for isolation. Until artifact isolation becomes a default rather than a feature you build yourself, the next serving runtime will re-open this flaw the day it adds revision pinning.

A cross-link note, because the brief asked for it and because this is where I must not overreach: the multi-user session and kernel-level tenant-isolation story (the continuous-batching internals, the GPU memory pool as shared memory, the batch-composition attacks) is covered in the vLLM tenant-isolation piece in this pillar, and I am not restating it here. This flaw is the artifact boundary; that piece is the data plane. They are related, they are not the same, and I am keeping them separate so an operator reading this does not walk away thinking I covered the kernel-isolation question. I did not. That piece did.

Detection command references

The commands below are lifted from the verification synthesis and kept at read-only diagnostic level. They are grouped by the flaw they diagnose; one command may appear under more than one flaw where the overlap is obvious. These are copy-paste starting points for your own hardware. Confirm each works in your deployment before you rely on it, and treat any hit as a finding to investigate, not an exploit. I am not including anything that would work against a live target as an attack; the one reachability probe is a diagnostic question (does this namespace reach the metadata service?), not a credential grab.

Flaw 1: port and bind audit (unauth 0.0.0.0 + operator credential)

# Every listening TCP socket with its owning process:
ss -tlnp | grep LISTEN

# Flag non-localhost bindings on anything that is a runtime or MCP server:
ss -tlnp | awk '$4 ~ /^0\.0\.0\.0:/ && NR>1 {print}'

# Operator tokens leaked into process command lines (llama.cpp, Ollama, vLLM, MCP):
sudo grep -hR /proc/*/cmdline 2>/dev/null | tr '\0' '\n' | grep -iE '(api.?token|bearer|secret|password)' || true

# Systemd unit files holding tokens next to a runtime service:
grep -rhE 'token=|API_KEY=|SECRET=' /etc/systemd/system/*.service 2>/dev/null

# Docker Compose .env files carrying common credential keys:
find /opt /home -maxdepth 4 \( -name '*.env' -o -name '.env*' -o -name 'docker-compose.yml' \) 2>/dev/null \
  | xargs grep -lE '(ARGOCD_API_TOKEN|MCP_|OPENAI_API|ANTHROPIC_API_KEY|LITELLM_MASTER_KEY)' 2>/dev/null

What you are looking for: any runtime or MCP server on 0.0.0.0, especially where a token string appears in the process environment, the unit file, or a .env next to the binary. The proxy in front matters: if LiteLLM sits between public traffic and the runtimes, verify the runtimes themselves are bound to localhost and only the proxy is wide, and verify the proxy is actually enforcing its key. A wide runtime behind an unenforced proxy is still a wide runtime.

Flaw 2: deserialization surface audit (pickle / model-file parsing)

# Standalone pickle/PKL artifacts on the system that a loader might pick up:
find / -maxdepth 5 \( -name '*.pickle' -o -name '*.pkl' \) -type f 2>/dev/null \
  | grep -vE '__pycache__|/usr/' || true

# Model-load code paths that parse GGUF / SAFETENSORS / pickle in the serving stack:
grep -rhiE 'gguf|safetensors|pickle\.loads|load_tensor|deserialize_tensor|unmarshal' \
  /opt/*/lib/python*/site-packages/ 2>/dev/null | head -30

# Is the default model-load directory writable by non-root? (It should not be.)
ls -ld "$(dirname "$(command -v ollama 2>/dev/null || echo /opt/ollama)")" 2>/dev/null
ls -ld "$(command -v llama-server 2>/dev/null || echo /opt/llama.cpp)" 2>/dev/null

What you are looking for: a runtime that will load a .gguf or .safetensors file dropped into a directory anyone on the box can write to, without checking the file's hash against an operator-supplied manifest. The clean signal is the absence of a verification step between "file arrived" and "file loaded." If the load path is writable by a non-root user and there is no hash gate, the parser's untrusted input has an inbound door.

Flaw 3: IMDS reachability and redirect behavior (SSRF)

# Can this host's network namespace reach the cloud metadata service?
# (Diagnostic: is the SSRF target even reachable from here? Expected: "unreachable" on a home LAN.)
curl -s --max-time 3 http://169.254.169.254/latest/meta-data/ || echo "IMDS unreachable"

# If your runtimes are containerized, test from inside each container's namespace:
for c in $(docker ps -q); do
  n=$(docker inspect -f '{{.Name}}' "$c")
  echo "== $n =="
  docker exec "$c" sh -c 'curl -s --max-time 3 http://169.254.169.254/latest/meta-data/ 2>/dev/null || echo "IMDS unreachable"'
done

# Do the fetch paths in your runtimes follow redirects on user-supplied URLs?
grep -rhiE 'allow_redirects|verify_redirect|requests\.(get|post)\(' \
  /opt/*/lib/python*/site-packages/mlflow/ /opt/*/lib/python*/site-packages/vllm/ 2>/dev/null | head -15 || true

What you are looking for: any service that can reach 169.254.169.254 from its own namespace and makes outbound calls on user-influenced URLs. On a home LAN the metadata service is not reachable, so the "IMDS unreachable" line is the healthy state. The risk on a home rack is a container that is on a VPC network, or a proxy that forwards user URLs to internal addresses. If the curl returns metadata, that namespace is an SSRF source and you need to restrict its egress or disable the endpoint per vendor guidance.

Flaw 4: token reuse and per-session auth (MCP)

# Every env var that looks like a token across running containers:
docker inspect $(docker ps -q) --format '{{.Config.Env}}' 2>/dev/null \
  | tr ',' '\n' | grep -iE 'token|api\.?key|bearer' || true

# MCP server config files with stored credentials:
find ~ /etc -name 'mcp*.json' -o -name '*.env' 2>/dev/null \
  | xargs grep -lE '_TOKEN=|api.?key.*=' 2>/dev/null

# Is the proxy in front actually enforcing a per-request key?
grep -rhE 'LITELLM_MASTER_KEY|AUTHORIZED_KEYS|AUTH_TOKEN' \
  /opt/litellm/ /etc/systemd/system/litellm* /home/*/.config/litellm/ 2>/dev/null | head -10 || true

# Is any MCP tool surface reachable without an inbound bearer key?
# (Listens + a no-auth probe to the local address. Diagnostic only — do not point this at remote hosts.)
ss -tlnp | grep -iE ':(31915|3000|808[0-9]|786[0-9])' | head

What you are looking for: an MCP server holding a token in its environment, bound to an interface beyond localhost, that accepts tool calls without a bearer key on the inbound request. The mitigation test is concrete: send an unauthenticated request through your proxy and confirm it returns 401 before reaching any backend. If an unauthenticated request reaches the MCP server, Flaw 4 is live on that rack.

Flaw 5: artifact-boundary and multi-user check (serving)

# Which models are loaded and who can list them without a per-call key:
curl -s --max-time 2 http://localhost:11434/api/tags 2>&1 | head -5 || true
curl -s --max-time 2 http://localhost:8000/v1/models 2>&1 | head -5 || true

# Does your vLLM deployment actually pin revisions, or just name them?
ps aux | grep -iE 'vllm|revision|code-revision' | grep -v grep || true

# Cross-check a pinned revision against the remote, if you track it by repo:
# git ls-remote --heads <repo-url>

What you are looking for: a serving API reachable without a per-call bearer token that lists models or exposes loading state, and a --revision flag whose value is a branch name rather than a commit hash. The pin-audit is the evergreen part: --revision main is not a pin, it is a pointer that can move. If you are serving to more than one user, verify the artifact-resolution path actually roots at a pinned commit, and snapshot the resolved digest so a later audit can prove what was loaded. On a single-operator rack this section is mostly a "you are not at risk yet" check, and knowing that is the point.

The durable operator checklist

These are the items that stay true as runtimes ship and get replaced. They are written against the flaw class, not the CVE, so the next runtime that re-introduces the class is already covered by a checklist you ran last quarter. Run them quarterly, not just at setup: the wave in this piece is, in large part, the list of things that were "fine at setup" and were not.

Flaw 1: bind and credential exposure

  1. Quarterly bind audit. ss -tlnp and flag every runtime or MCP server on 0.0.0.0. Force-bind non-public runtimes to 127.0.0.1 and put the proxy in front if they must be reached across the network. A runtime on a wide interface that is not deliberately public is a finding.
  2. Credential sweep. Scan systemd units, Docker Compose .env, and /proc/<pid>/cmdline for any token sitting next to an inference or MCP process. Rotate immediately on discovery. The token being used by the service is not a reason it should be readable by anything else on the box.

Flaw 2: deserialization and model-file parsing

  1. Model-load integrity gate. No model file loads from a URL, a mirror, or a third-party repo without a hash or signature check against an operator-supplied manifest. The download path and the load path are two different boundaries, and the load path is the one that matters. If a .gguf can be dropped into the load directory by a non-root user, close that door.
  2. Build-aware update cadence. Apply upstream fixes within 72 hours of the advisory, and for build-based projects like llama.cpp, track the commit, not a version tag. b8146 and b8492 are the floors in this wave, and "latest release" in a package manager that lags the repo is not the same as "latest build." Watch the runtime's GitHub security tab, not the package index.

Flaw 3: SSRF

  1. IMDS reachability test. curl http://169.254.169.254/latest/meta-data/ from every container and host running a runtime. The healthy answer on a home LAN is "unreachable." If a namespace returns metadata, restrict its egress or disable the endpoint. This is a diagnostic, not a target: the goal is to know which of your boxes is an SSRF source.
  2. Fetch-path discipline. Every outbound call a runtime makes on user-influenced input must not follow redirects without re-validating the target, and must refuse link-local and metadata ranges. allow_redirects=False (or equivalent) on user-supplied URLs is the floor, not the ceiling.

Flaw 4: token reuse in MCP

  1. Per-session auth, no token doubling. No MCP server accepts a tool call without verifying an inbound bearer token, and the outbound operator token (the Argo CD token, the forge token) is never the inbound credential. The proxy in front enforces a per-request key and rejects unauthenticated requests before they reach a backend.
  2. Token rotation on any leak. If a token appeared in a log, a cmdline, or a process environment at any point since the last rotation, rotate it and audit the sessions that used it in the window. "It only went in the environment" is not a non-leak; the environment is readable by process-level access.

Flaw 5: artifact-boundary isolation

  1. Per-call auth on multi-user serving endpoints. Every OpenAI-compatible endpoint (/v1/models, /v1/chat/completions) must require a valid per-key header, and an anonymous caller gets 401, not the model listing. If only one person uses the stack, this is a cheap habit to build before it stops being one person.
  2. Revision pin audit. For any deployment that pins a model, verify the pin is a commit hash, not a branch name, and snapshot the resolved digest so a later audit can prove what was actually loaded. --revision main is a pointer, not a pin.

Cross-cutting

  1. Network-namespace hygiene. Every runtime service runs with the minimum network interfaces it needs. No host-network mode on a model-serving container unless you have a specific reason and a specific firewall rule for it. The less of the rack a runtime can see, the smaller the blast radius when one of the five flaws fires.
  2. Kill-switch inventory. Document how to stop each runtime's HTTP transport in under thirty seconds. For llama.cpp it is killing llama-server; for Ollama, vLLM, Triton, and each MCP server there is an equivalent. If a flaw is actively firing, you want the off switch to be a documented command, not a search.

Worked example: the Malwlab rack mapped against the five

This is the section the rest of the piece is for. I am mapping each flaw against the actual rack: Qwen3.6 on llama.cpp, an Ornith sidecar, a LiteLLM proxy, and a set of MCP servers with stored tokens. I am being careful to distinguish what I have verified on this box from what I would verify if I were sitting at the keyboard, because the difference is the whole point of a worked example. Where I am describing a check to run rather than a result I have, I say so.

Flaw 1: the wide bind. The shape on this rack is a LiteLLM proxy in front, with llama.cpp (and an Ollama box) behind it. The healthy configuration is the runtimes bound to localhost and the proxy as the only wide listener, with the proxy enforcing its key. The risk is not the proxy. It is what is also listening. If any MCP server, or the Ornith sidecar, is bound to 0.0.0.0 on the same host with a token in its environment, it is exposed to every host on the LAN independent of the proxy, because the proxy only covers the traffic that goes through it. The check is the Flaw 1 bind audit, run against the actual process list, and the finding I would act on is any runtime or MCP listener on 0.0.0.0 that is not the proxy. I have not run the live ss -tlnp in this draft; the check is the deliverable here, and the operator result is what changes the posture.

Flaw 2: the model load. This is the one that is inherent to the rack, because Qwen3.6 loads through llama.cpp's GGUF parser, which is exactly the code path CVE-2026-27940 and CVE-2026-34159 live in. Every GGUF the rack loads (including Qwen3.6) goes through gguf_init_from_file_impl() and the tensor deserialization path. The mitigation is not a runtime change; it is a process change: verify the hash of every model file against a manifest before it enters the load directory, and confirm the llama.cpp build is at or past the b8492 floor that clears the 27940 and 34159 class. If models are being pulled from mirrors or third-party repos, the download is the untrusted input and the load directory must not be writable by anything that does not already trust the manifest. This is the flaw I would call "unavoidable without an external verification step," because the parser is doing its job. The job is just defined to trust the file.

Flaw 3: the metadata reach. This is conditional on the rack's network, and I am marking it as a check rather than asserting a state. LiteLLM makes outbound calls to provider APIs, and if any of those, or any webhook or registry-verification path, is pointed at a user-influenced URL, the SSRF surface exists the moment the calling namespace can reach a metadata address. On a home LAN the metadata service is not reachable, so the expected result of the IMDS probe is "unreachable," and the risk concentrates in any container that is on a VPC network or any proxy path that forwards user URLs to internal addresses. The check is the per-namespace IMDS probe from the Flaw 3 block, and the posture changes only if one of those probes returns metadata. I have not run it live for this draft; it is a five-minute check and the answer determines whether this flaw is a tonight item or a not-applicable one.

Flaw 4: the stored tokens. This is the flaw that is most concretely present on the rack, and the one I would weight highest for a homelab, because the setup is literally "MCP servers with stored tokens." If those servers hold forge or GitOps tokens in their environment and are reachable from other hosts on the LAN without an inbound bearer requirement, then every request to them executes as my operator identity, and the proxy only helps if it is actually in the path and actually enforcing its master key per request. The single most important mitigation for this rack is the one test: send an unauthenticated request through the LiteLLM proxy and confirm it returns 401 before it reaches any backend. If it does not, the stored tokens are reachable without auth and this flaw is live. The Ornith sidecar is in scope here too. If it exposes an HTTP surface for orchestration with a token in its environment, it is an MCP-shaped server for Flaw 4 purposes and gets the same per-request auth check.

Flaw 5: the artifact boundary. On a single-operator rack like this one, this flaw is dormant. There is no second user whose sibling artifacts could bleed into a pinned revision, so the exploitation path that CVE-2026-47155 describes has no second party to exploit it against. It becomes relevant the day multi-user model routing is added, if another operator's requests start routing through the same engine or if models start loading from a shared registry where "pinned revision" and "pinned model" diverge. Until then the correct posture is to monitor for that change and to pin by commit hash (not branch name) now, so that the day multi-user arrives, the artifact boundary is already rooted at a digest you can audit. I am stating "dormant" plainly, because the honest read of a single-operator setup is that this flaw has no live exploitation path today, and claiming otherwise would be worse than the truth.

Overall posture, in one paragraph. The Malwlab rack has Flaw 2 inherent (the GGUF parser is the load path, and there is no way around it except hash-gating every model before it loads), Flaw 4 concretely present and the highest-weight item (stored MCP tokens behind a proxy that must be verified to enforce per-request auth), Flaw 1 present-within-the-LAN until the bind audit confirms every non-proxy listener is localhost, Flaw 3 conditional on the network namespace and resolvable with a five-minute IMDS probe, and Flaw 5 dormant until multi-user serving is introduced. The proxy is doing real work on this rack, but a proxy only closes the flaws for the traffic that passes through it, and it does nothing for a listener that is wide and not behind it. That is the through-line: the proxy is the mitigation for the public boundary, and the five flaws mostly fire on the internal boundary, where the proxy is not looking.

Open issues and future work

A few things this piece deliberately leaves open, so the taxonomy can be extended rather than pretending to be finished.

The user-level tenant claim is still unsourced. Flaw 5 is documented here at the artifact boundary only, because that is what the primary evidence supports. The cross-user, session-level, kernel-isolation claim (that one user's request can read another user's data in a shared engine) is not something I could ground in the fixed evidence set, and I would rather mark it open than dress it up. The vLLM tenant-isolation piece in this pillar covers the kernel-level mechanism in detail, and the two pieces should be reconciled against a single primary-source record before either is cited for the cross-user data-exposure claim specifically. If a future disclosure confirms a batch-level cross-tenant leak with a primary source, Flaw 5 should be split: artifact-boundary isolation (documented) and data-plane isolation (pending a citable source).

The MCP transport has no identity model, yet. Flaw 4 is, at the root, a specification gap, not just a deployment gap. The current MCP transports do not carry per-session identity, so every server that exposes a network surface inherits the "one operator token, everyone's session" problem. The taxonomy should track when the MCP spec adds per-session identity or a mandatory inbound-credential requirement, because that is the point at which Flaw 4 stops being "operator must enforce it at the proxy" and starts being "the transport enforces it." Until then the proxy is the mitigation, and the checklist item 7 is the only durable control.

Build-based projects make the "fix version" a moving target. llama.cpp's b8146 and b8492 floors are the cleanest example of a problem the taxonomy has to keep re-solving: for a project that ships builds rather than version tags, "the fixed version" is a commit, and the commit moves as the repo moves. The checklist item 4 (track the commit, not the tag) is the durable control, but the specific floor has to be re-verified whenever a new build-based CVE lands, because the new floor may be higher than the one this piece quotes. The reviewer should treat the specific build numbers as point-in-time and re-check the current floor against the runtime's security tab at publish time.

Two source conflicts I am carrying, not resolving. The nginx-ui affected-version conflict (official GHSA "2.3.5 and prior, no patch" vs. the finder's "fixed in 2.3.4") and the Azure MCP Server IMDS mechanism (verified scope is "SSRF elevates privileges," the specific IMDS detail not confirmable from the JS-only vendor page) are both flagged inline and in the verification notes. Neither changes a flaw's framing, but both are the kind of thing an operator acting on this piece should see as "the sources disagree, here is the position I am citing."

How the taxonomy extends. The test for a new runtime, when it ships, is not "does it have a CVE" but "does it hit at least two of the five flaws by default." My working expectation, from the pattern in this piece, is that it will: it will bind wide until told otherwise, it will load a model file without a signature gate, it will add a "test this connection" fetch, it will hold one operator token for every session, and it will not isolate artifacts by default. A new runtime that explicitly argues against even two of those (that binds localhost by default, that hash-gates model loads, that refuses link-local fetches, that requires per-session identity, that roots artifacts at a pinned digest) is the one worth writing up as the exception, because it is the one that proves the five flaws are design choices and not laws of physics.

That is the evergreen claim, and the reason this piece is a pattern and not a changelog: the CVE numbers in this piece will be stale within a year, the runtimes will be replaced, and the five flaws will still be there, waiting in the defaults of whatever ships next. The checklist is the part that does not go stale.

Sources

The inline numbers point into this list. Primary sources (NVD, vendor GHSAs, NVIDIA product-security, CISA KEV) are prioritized over commentary; verbatim quotes in the body are lifted from the verification memo, which recorded them against each source at retrieval time.

1. https://nvd.nist.gov/vuln/detail/CVE-2024-37032: NVD: CVE-2024-37032 (Ollama "Probllama")

2. https://nvd.nist.gov/vuln/detail/CVE-2026-27940: NVD: CVE-2026-27940 (llama.cpp GGUF integer overflow)

3. https://nvd.nist.gov/vuln/detail/CVE-2026-41523: NVD: CVE-2026-41523 (vLLM assert-bypass RCE)

4. https://nvd.nist.gov/vuln/detail/CVE-2026-47155: NVD: CVE-2026-47155 (vLLM Artifact Pin Decay)

5. https://nvd.nist.gov/vuln/detail/CVE-2025-47277: NVD: CVE-2025-47277 (vLLM PyNcclPipe deserialization)

6. https://nvd.nist.gov/vuln/detail/CVE-2026-22778: NVD: CVE-2026-22778 (vLLM multimodal RCE chain)

7. https://nvd.nist.gov/vuln/detail/CVE-2026-34159: NVD: CVE-2026-34159 (llama.cpp deserialize_tensor RCE)

8. https://nvd.nist.gov/vuln/detail/CVE-2025-53630: NVD: CVE-2025-53630 (llama.cpp GGUF parser overflow)

9. https://nvd.nist.gov/vuln/detail/CVE-2026-24207: NVD: CVE-2026-24207 (Triton auth bypass)

10. https://nvd.nist.gov/vuln/detail/CVE-2026-47628: NVD: CVE-2026-47628 (Triton unbounded resource DoS)

11. https://nvd.nist.gov/vuln/detail/CVE-2026-24147: NVD: CVE-2026-24147 (Triton config upload path traversal)

12. https://nvd.nist.gov/vuln/detail/CVE-2026-24215: NVD: CVE-2026-24215 (Triton DALI DoS)

13. https://nvd.nist.gov/vuln/detail/CVE-2026-64849: NVD: CVE-2026-64849 (MLflow webhook SSRF)

14. https://nvd.nist.gov/vuln/detail/CVE-2026-33032: NVD: CVE-2026-33032 (nginx-ui "MCPwn")

17. https://nvd.nist.gov/vuln/detail/CVE-2026-82456: NVD: CVE-2026-82456 (argocd-mcp unauth bind)

18. https://github.com/advisories/GHSA-8hqg-whrw-pv92: Ollama GHSA: Probllama fix (0.1.34)

19. https://github.com/ggml-org/llama.cpp/security/advisories/GHSA-3p4r-fq3f-q74v: llama.cpp GHSA: CVE-2026-27940

20. https://github.com/vllm-project/vllm/security/advisories/GHSA-q8gq-377p-jq3r: vLLM GHSA: CVE-2026-41523

21. https://github.com/vllm-project/vllm/security/advisories/GHSA-3ww4-5jv9-j5gm: vLLM GHSA: CVE-2026-47155

22. https://github.com/vllm-project/vllm/security/advisories/GHSA-hjq4-87xh-g4fv: vLLM GHSA: CVE-2025-47277

23. https://github.com/vllm-project/vllm/security/advisories/GHSA-4r2x-xpjr-7cvv: vLLM GHSA: CVE-2026-22778

24. https://github.com/ggml-org/llama.cpp/security/advisories/GHSA-j8rj-fmpv-wcxw: llama.cpp GHSA: CVE-2026-34159

25. https://github.com/ggml-org/llama.cpp/security/advisories/GHSA-vgg9-87g3-85w8: llama.cpp GHSA: CVE-2025-53630

26. https://github.com/advisories/GHSA-gfjf-7c33-r54h: Triton GHSA: CVE-2026-24207 (auth bypass)

27. https://github.com/advisories/GHSA-j87r-h67h-c626: Triton GHSA: CVE-2026-47628 (DoS)

28. https://github.com/advisories/GHSA-j364-q6wp-mwj2: Triton GHSA: CVE-2026-24147 (config upload info disclosure)

29. https://github.com/advisories/GHSA-f637-j435-xwhv: Triton GHSA: CVE-2026-24215 (DALI DoS)

30. https://github.com/advisories/GHSA-7gwp-5pfp-969j: MLflow GHSA: CVE-2026-64849

31. https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-h6c2-x2m2-mwhf: nginx-ui GHSA: CVE-2026-33032

35. https://www.cisa.gov/known-exploited-vulnerabilities-catalog: CISA KEV catalog

36. https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json: CISA KEV raw feed (catalog 2026.08.31)

37. https://github.com/NVIDIA/product-security/tree/main/2026/5816: NVIDIA product-security bulletin 5816 (Triton, CVE-2026-24147)

38. https://github.com/NVIDIA/product-security/tree/main/2026/5828: NVIDIA product-security bulletin 5828 (Triton, CVE-2026-24207 / 24215)

39. https://github.com/NVIDIA/product-security/tree/main/2026/5865: NVIDIA product-security bulletin 5865 (Triton, CVE-2026-47628)

40. https://github.com/argoproj-labs/mcp-for-argocd/security/advisories/GHSA-rp45-5x3v-48mr: argocd-mcp GHSA: CVE-2026-82456 (fix 0.9.0)

42. https://github.com/mlflow/mlflow/commit/ba949522477cbd5915aa55d29b0cfad7d5ddf939: MLflow: DNS-rebinding SSRF fix commit

43. https://github.com/mlflow/mlflow/releases/tag/v3.15.0: MLflow 3.15.0 release

44. https://github.com/mlflow/mlflow/pull/24258: MLflow PR #24258

46. https://www.vulncheck.com/advisories/argocd-mcp-0.8.0-authentication-bypass-via-unauthenticated-http: VulnCheck: argocd-mcp 0.8.0 auth bypass

47. https://websec.net/blog/cve-2026-33032-unauthenticated-nginx-ui-mcp-takeover-69e1200f9fceb1f3fbe9c47f: websec.net: CVE-2026-33032 analysis (confirms affected 2.3.5 and prior, no public patch at publication)

50. https://nvd.nist.gov/vuln/detail/CVE-2026-26118: NVD: CVE-2026-26118 (Azure MCP Server SSRF)

51. https://github.com/advisories/GHSA-hhfx-wfvq-7g9c: Azure MCP GHSA: CVE-2026-26118

  • local-llm-security-hardening-self-hosted-ai-infrastructure — the single-deployment threat model. This piece is the cross-runtime pattern; that piece is the one-rack threat model. Read together, the threat model is the frame and the five flaws are the content.
  • vllm-tenant-isolation piece — the multi-user tenant isolation internals in one runtime (continuous batching, the GPU memory pool, batch-composition). This piece's Flaw 5 is the artifact boundary only; the data-plane/kernel isolation is in that piece.
  • the-model-file-is-the-payload — GGUF format forensics. This piece's Flaw 2 is the parser class across runtimes; that piece is the format.
  • detection-guidance-exposed-mcp-servers-homelab — MCP exposure detection. This piece's Flaw 4 detection commands are the per-flaw subset; that piece is the full MCP exposure audit.
Topics: