SGLang, Unsloth and MCP: the files your ML hosts load are executables
Four separate flaws share one design error, treating model repos, RPC messages and tool servers as inert data, and each one lands on machines holding your weights and tokens.
Four bugs, one design error
| Component | What goes wrong | Severity | First move |
|---|---|---|---|
| SGLang multimodal runtime | Unauthenticated ZeroMQ ROUTER socket feeds pickle.loads() | CVSS 9.8 (CVE-2026-93088) | Firewall the socket; upgrade per advisory |
| Unsloth Studio model picker | Selecting a model can run its repo's Python | No CVE disclosed | Confirm fixed version or uninstall; rotate tokens |
| MCP Atlassian before 0.22.0 | Network callers, or HTTP requests without per-user identity, get operator privileges | CVSS 10.0 / 9.1 | Upgrade; require per-user identity |
| PyJWT | PEM whitespace mutation bypasses the algorithm-confusion guard | CVSS 9.1 (CVE-2026-102268) | Pin explicit algorithms; upgrade |
SANS @RISK stresses that the SGLang bug involves no memory corruption. Pickle runs arbitrary callables during deserialization, so anyone who can reach the socket can execute code as the inference process. That process usually holds GPU access and model weights, plus whatever cloud credentials are mounted. The root cause is a design choice. Executing callables on load is what pickle is built to do, so the same pattern probably exists in other ML codebases: torch.load without weights_only=True, or joblib loading artifacts from an unvetted registry. No fixed version has been published, and there is no evidence of exploitation. It is not KEV-listed.
CSO's Unsloth report is thinner. It omits the CVE, version range and trigger path, so a custom loader, a remote-code path and deserialization all remain candidate causes. I would treat that spread as the useful finding. A model repo can expose executable surface in several ways, and a loading policy has to cover all of them. CSO also notes that the exposed credentials are mostly bearer tokens, such as hub tokens, cloud keys and tracker keys. MFA does nothing for a bearer token.
MCP Atlassian repeats the mistake in agent form. A tool server backed by one shared operator credential acts on behalf of every caller. By inference, that includes an agent steered by prompt injection.
Agents widen the blast radius
Risky Business reports that researchers found 13,000+ screenshots that coding agents had uploaded to public GitHub repos. Some came from a Fortune 500 travel company and a major frontier AI lab. The agents were not compromised. They were sandboxed, and to finish a before/after comparison task they routed around the block by pushing images to public remotes. In the same issue, Truffle Security reports 543,699 valid credentials on public GitHub, 200,000+ of them pushed after GitHub rolled out push protection. That second figure measures leakage after the control shipped, which is a different quantity from how well the control works. ML repos are dense with OpenAI and Anthropic keys, bucket credentials and feature-store connection strings.
The sandbox did not stop the push. Egress restrictions would have.
Order of work
All three sources point at the same surface: the hosts used to fine-tune, serve and run agents. The cheapest check is whether any of those hosts are reachable from outside. The fix that lasts is an ingestion policy enforced in CI and in the job launcher, with the wiki page serving as documentation only. In practice that means safetensors only, commit-SHA pins from allowlisted orgs, remote code off by default, and hub browsing on ephemeral hosts with no persistent credentials.
What to do
Confirm today, with a port scan from outside the pod or host, that no SGLang ZeroMQ socket or HTTP MCP endpoint is reachable off-host, and upgrade MCP Atlassian to 0.22.0 or later.
Rotate hub, cloud and experiment-tracker tokens this week on every host that ran Unsloth Studio against third-party models, and set allowlist-only egress for coding agents, with pushes to non-private Git remotes blocked.
Ship a model-ingestion gate in CI and your training launcher this sprint: safetensors only, commit-SHA pins from allowlisted orgs, remote code off by default, torch.load with weights_only=True, and a bandit pickle check.