One curl Kills the Server; One Model File Overflows the Heap: FastLLM and SGLang, 19 October

Four CVEs published on 19 October 2026 hit the two ends of the inference stack: the model files going in, and the server endpoints going out. FastLLM (ztxz16/fastllm, 5,108 stars, C++) carries a heap buffer overflow in its own safetensors parser (CVE-2026-112107, published 12:17:00Z) and another in its GGUF string reader (CVE-2026-112108, 12:17:01Z) — both with public proofs of concept, both reported on 4 October, both still open with zero comments fifteen days later. SGLang (37,381 stars) carries two unauthenticated denial-of-service records — CVE-2026-112082 (CVSS 7.5, published 06:17:23Z) against the expert-distribution recorder endpoints and CVE-2026-112083 (5.5) against the weight exporter — with the fix pull request sitting open and unmerged since 1 October. We read all four NVD records, both FastLLM issues, the SGLang issue and fix PR, and the cited code, first-hand.

FastLLM: shape says one thing, offsets say another, nobody checks

FastLLM implements its own safetensors parser rather than using a shared library, and the constructor of SafeTensorItem in src/model.cpp — still present on master today — reads exactly as the reporter describes:

len = 1; for (auto &it : shape) { len *= it; } bytes = this->data_offsets[1] - this->data_offsets[0];

len comes from the declared tensor shape; bytes comes from the declared data offsets; the two attacker-controlled values are never reconciled. Downstream, CreateBuffer() allocates from one and reads the other — the issue’s gadget is a header declaring shape [1] with dtype F32 beside offsets spanning megabytes, so a small allocation receives a large fread(). The dtype ladder in CreateBuffer shows why the class is broad rather than a single bad line: the F32, U8, I64 and fastllm-native branches each pair an allocation expression with a read expression, and the invariant relating them lives nowhere in the struct.

The GGUF bug is smaller and purer. GGUFBuffer::ReadString() in third_party/gguf/gguf.cpp, quoted in full from master:

uint64_t len = Read<uint64_t>(); std::vector<char> v; v.resize(len + 5); int ret = fread(v.data(), 1, len, f);

The length is 64 bits straight from the file. It sizes the allocation and the read, with five bytes of headroom doing nothing against a near-2^64 value: len + 5 wraps to a handful of bytes while fread still copies len. Metadata parsing — the part of the loader that runs before any tensor is touched, on every file open — is the trigger. Both issues carry attached PoC archives, both NVD records note the exploit is public, and both state the project was informed early and has not responded. The repository was pushed as recently as 19 October; the issues, opened 4 October, have had no reply.

One scoring note, recorded rather than averaged per house convention: VulDB rates 112107 at 6.3 under CVSS 3.1 and 2.1 under CVSS 4.0 for a remotely triggerable heap overflow with a published PoC. Whatever the 4.0 metric combination discount is doing, a two-point-“low” on a memory-corruption primitive in a model loader understates the risk. Treat the 6.3 as the working number and the PoC as the ground truth.

SGLang: the diagnostic routes that are always on and never guarded

CVE-2026-112082 is the more instructive of the SGLang pair because the reporter’s write-up is complete and the failure is architectural. /start_expert_distribution_record, /stop_expert_distribution_record and /dump_expert_distribution_record are registered on every server and accept both GET and POST. On a server started without --expert-distribution-recorder-mode — i.e. the normal case — each raises an uncaught exception inside the scheduler process: the scheduler child dies, the supervisor takes SIGQUIT, and the whole server exits. Every later request fails; /health is unreachable. The engine even knows what is wrong — the traceback ends in Exception: Please set ServerArgs.expert_distribution_recorder_mode to use ExpertDistributionRecorder — and throws that knowledge away in the process of dying.

The access-control detail is what makes it a CVE rather than a crash bug: the routes are AuthLevel.ADMIN_OPTIONAL, so on a server without --api-key no credential is needed at all. One request, no body, no key, and the serving process is gone. The reproduction in the issue is two lines: launch on Qwen/Qwen3-0.6B, then curl -X POST http://127.0.0.1:30000/dump_expert_distribution_record. The reporter’s proposed fix is one sentence long: “A 4xx saying ‘the expert-distribution recorder is not enabled’ is all that is needed.” The actual fix PR (#42098, “Reject disabled expert recorder controls before scheduler dispatch”) has been open since 1 October with zero comments and no merge — eighteen days in which every default SGLang deployment carried a one-request kill switch on an admin-optional route. CVE-2026-112083 extends the pattern to the weight exporter: manipulating group_name in WeightExporter.send_weights_to_remote_instance yields remote denial of service, fix likewise awaiting acceptance.

Note the shared shape with this morning’s AgentMesh pair: capability-gated code reachable without the capability. The recorder endpoints assume a mode that was never enabled; the ingress assumed authentication that was never required. Fail-open is not a property of one project’s bad week; it is what optional-everything server design converges on when the disabled path is still routable.

What to do

For FastLLM: treat model files as untrusted input to a C++ parser until a fix lands — which, fifteen days in with no maintainer response, means until further notice. Load models only from sources you already trust with code execution, sandbox the loader, and watch issues #758 and #759 rather than version numbers (the NVD version ceilings for the two records even disagree with each other: “up to 1.8.2” versus “up to 0.1.8.2” — read the issues, not the metadata). For SGLang: put --api-key on every reachable server now, restrict the recorder and exporter endpoints at the reverse proxy if you cannot upgrade, and track PR #42098. More generally, inventory your inference servers’ diagnostic and admin routes and check each one’s auth level against the assumption it is reachable — the SGLang reporter’s surprise (“surprised they are available on all servers?”) is available to anyone who reads their own route table.

None of the four is in the CISA KEV catalogue (checked directly, 1,749 entries, zero hits), and no exploitation beyond the published proofs of concept has been reported. All four NVD records carry public-exploit flags from the assigning CNA.

Our verification was read-only. All four CVE identifiers, publication timestamps (2026-10-19T06:17:23Z and 2026-10-19T12:17:00/01Z), vulnStatus values, the cna@vuldb.com source, CWE assignments, CVSS 3.1 and 4.0 vectors and scores, descriptions and references were read first-hand from the NVD 2.0 API; FastLLM issues #758 and #759 (titles, 4 October creation, open state, zero comments, PoC attachments) and SGLang issue #42071 (full body including the traceback, reproduction and auth-level analysis) and PR #42098 (title, 1 October creation, open state, unmerged, zero comments) from the GitHub API; the SafeTensorItem constructor, the CreateBuffer allocation/read pairing and the complete ReadString function quoted verbatim from fastllm master fetched via raw URLs; the recorder-mode guard lines from SGLang’s expert_distribution.py likewise; repository metadata (5,108 and 37,381 stars, languages, push dates, not archived) from the GitHub API. KEV status was checked directly against the published catalogue. Brave Search was used for discovery only. We built nothing, loaded no model file, started no server, sent no request, and executed no proof of concept.

Sources: