Xinference 4.1.0 reached PyPI on October 25 with four security advisories attached, none of them carrying a CVE. The one the maintainers label Critical, GHSA-2gq8-2q98-6w29, lets a CosyVoice model config run code on a worker at parse time. The High, GHSA-v43j-w7xm-2vwh, lets whoever reaches an uninitialized REST API first become the admin. Both are fixed in 4.1.0, but the fix for the first is an opt-in trust flag rather than a sandbox, and the fix for the second does nothing about an admin an attacker has already created. The fix for a third problem, the unauthenticated actor transport addressed in the October 16 release, is still off by default after this upgrade too. S5 Labs has not tested any of it; what follows is read from the advisories, the release notes and the package indexes. Xinference v4.1.0 release · PyPI, xinference 4.1.0
What 4.1.0 fixes, and what it only enables
| Advisory | Severity | Affected | Fixed by | What upgrading alone does |
|---|---|---|---|---|
| GHSA-2gq8-2q98-6w29, CosyVoice HyperPyYAML code execution | Critical (maintainers’ label; no CVSS) | ≤ 4.0.1 | 4.1.0, PR #5765 | Blocks custom CosyVoice sources until XINFERENCE_TRUST_REMOTE_CODE=1 is set on the worker |
| GHSA-v43j-w7xm-2vwh, unauthenticated first-admin creation | High, CVSS 3.1 8.1 | ≥ 3.0.0, < 4.1.0 | 4.1.0, PR #5703 | Requires a setup token from the startup log; does not remove an existing account |
| GHSA-3jw7-r8gq-5ggj, auto-register path reads and Flexible launcher imports | Medium, 5.3 | ≥ 0.13.1, < 4.1.0 | 4.1.0, PR #5766 | Confines reads to model roots; extra launchers need an allowlist entry |
| GHSA-h97g-6mc6-66hm, raw worker errors in chat completions | Medium, 4.3 | < 4.1.0 | 4.1.0, PR #5767 | Returns a generic message; diagnostics stay in server logs |
| GHSA-2hj6-h88x-mv4j, CVE-2026-49950, unauthenticated actor transport | Critical, CVSS 4.0 9.3 (no CVSS 3.1 score in the GitHub record) | ≤ 4.0.1; 4.0.1 with XOSCAR_AUTH_KEY unset or empty stays affected, and the 4.1.0 notes say upgrading alone does not enable authentication | Mitigated, not patched: 4.0.1 with Xoscar 0.12.0+ and the key set, PR #5696 | Nothing. Authentication stays off until every peer has the same key |
Sources: the five advisories linked in the table and the v4.1.0 and v4.0.1 release pages. The optional fastapi-guard middleware in 4.1.0’s feature list (PR #5664) is not described as a fix for any of these.
The release sequence matters for anyone who pinned a version this month: 4.0.0 on October 9, 4.0.1 on October 16 (the Xoscar authentication backport, nothing else), 4.1.0 on October 25. Xoscar 0.12.0 shipped the same morning as 4.0.1; the latest Xoscar is 0.12.3. PyPI, xinference · PyPI, xoscar
CosyVoice: the config file is a program
The CosyVoice loader reads cosyvoice.yaml or cosyvoice2.yaml with HyperPyYAML. HyperPyYAML tags can execute code when the file is parsed, the advisory’s example being !apply:os.system, and the parse happens before any later model validation succeeds or fails. CosyVoice and CosyVoice2 share the trust boundary. The code runs with the worker’s privileges. GHSA-2gq8-2q98-6w29
The precondition is that the attacker gets the deployment to load a model directory or repository they control. Without inference authentication, an untrusted network client may reach the model-launch path directly. With authentication, the client needs whichever model-launch or registration permission applies. Registration is the part to think about: a registered custom model keeps its untrusted source, so a one-time registration by someone with that permission carries into every later launch. The original report also described repository-supplied configs and persisted registrations as additional paths. GHSA-2gq8-2q98-6w29
The fix in PR #5765 is a gate, not a parser change. Custom CosyVoice sources and explicit local model_path overrides now require XINFERENCE_TRUST_REMOTE_CODE=1 on the worker. The check runs before any download or vendor loading, an explicit path cannot inherit the provenance of a built-in model, and registered built-in hub or cache models keep working without the flag. Setting the variable on an older release does not produce this behavior; the gate exists only in 4.1.0. GHSA-2gq8-2q98-6w29 · PR #5765
The advisory is direct about what the flag is not: opting in “does not sandbox HyperPyYAML or make an untrusted source safe”. Set it on a worker and that worker is back to the 4.0.1 situation, which is the right trade only when you control every path to its launch and registration endpoints. The release page’s broader wording, “require explicit operator trust before loading custom sources or explicit local paths”, should not be read as a gate on every model family; the advisory scopes it to CosyVoice sources and explicit path overrides, and the release’s own upgrade note says the same. 4.1.0 also applies the trust policy to MOSS pipelines (PR #5769). GHSA-2gq8-2q98-6w29 · Xinference v4.1.0 release
For a worker that cannot be upgraded yet, the advisory’s workaround is the obvious one: limit launch and registration to trusted operators, restrict network access, and keep untrusted parties from supplying or modifying CosyVoice model directories or repositories. GHSA-2gq8-2q98-6w29
First admin: whoever arrives first
GHSA-v43j-w7xm-2vwh applies only when advanced authentication is enabled and the auth user store is empty, which is a fresh install or a deployment recreated without its persisted auth state. In that window, anyone with network access to the uninitialized REST API can create the initial admin, and from there manage users, API keys, settings and model serving. A deployment with an existing account rejects further first-run setup, but the window reopens whenever auth state is emptied or lost. The score is CVSS 3.1 8.1 with high attack complexity; the advisory publishes the vector and does not say why complexity is high. Our interpretation, not the advisory’s, is that the attacker has to get there before the operator does. Reporter: Paul White (Su1ph3r) of Cairn Security. GHSA-v43j-w7xm-2vwh
PR #5703 adds a server-generated one-time setup token. The API server prints it in its startup log; the operator enters it on the setup page or sends it as setup_token. A missing or wrong token is rejected before any password hashing. The token is rechecked at first-account creation and consumed when the account is created; a new setup cycle needs a new token, and the public setup-status response does not expose it. The release’s upgrade note is one line: “For fresh instances, use the setup token in the API server startup log”. A related 4.1.0 change, PR #5770, validates shared-store API keys against current state. GHSA-v43j-w7xm-2vwh · PR #5703 · Xinference v4.1.0 release
The part that is not fixed by upgrading is any admin that already exists. The advisory says so: “upgrading does not remove that account or its API keys”. If a deployment ran advanced auth with its REST port reachable while the store was empty, at any point since 3.0.0, the account list has to be audited rather than assumed. An operator with shell access can run the documented xinference-reset-auth-password command, then review accounts, API keys and configuration and revoke anything unauthorized. The two preventive measures are to restrict REST access to trusted operators until setup is finished, and to persist the auth database across container recreation so the window does not reopen on every redeploy. The advisory notes that its verification was API-level and describes the limits of that. GHSA-v43j-w7xm-2vwh
Actor transport: the key you have to set yourself
This one predates 4.1.0 and survives it. Xinference’s processes talk over Xoscar actor ports, and Xoscar deserializes Python objects from message headers or payloads with cloudpickle.loads before actor-level handling. An unauthenticated actor port therefore takes arbitrary objects from whoever can reach it, and it also accepts direct actor operations with no REST authentication or scope check, among them get_config, which returns pool topology, module configuration and subprocess environment dictionaries that may hold secrets, and stop, which shuts the pool down. Xinference’s HTTP API authentication does not protect these ports. The supplied distributed Compose configuration publishes 9999, 30001 and 30002. A single-node deployment is exposed if its actor ports are reachable by untrusted peers; a loopback listener limits access to local processes without authenticating them. GHSA-2hj6-h88x-mv4j · Xoscar GHSA-mmvj-m246-m9vf
The impact list is code execution as the Xinference process, access to its data and credentials, manipulation of model and cluster operations, and disruption; a compromised supervisor can reach connected workers, and what that means for the host depends on privileges, isolation and mounts. GHSA-2hj6-h88x-mv4j
Version 4.0.1 backported PR #5696, requires Xoscar 0.12.0 or later, and “introduces opt-in HMAC-SHA256 authentication of actor messages before Python object deserialization”. In keyed mode Xoscar verifies the HMAC over the framing metadata and the whole message, every payload buffer included, before deserializing. The release note puts it in three sentences: “Actor transport authentication is disabled unless a nonempty XOSCAR_AUTH_KEY is configured. Upgrading alone does not enable this protection. HTTP API authentication does not protect actor ports.” The 4.1.0 notes repeat the opt-in. Xinference v4.0.1 release · Xoscar GHSA-mmvj-m246-m9vf · Xinference v4.1.0 release
Turning it on is a cluster operation, not a config edit:
| Step | Detail |
|---|---|
| Upgrade every server | 4.0.1 or later (or the updated image) with Xoscar 0.12.0+ on every actor process, direct actor clients included |
| Generate one secret per deployment | python -c "import secrets; print(secrets.token_hex(32))" |
| Export it everywhere | The same XOSCAR_AUTH_KEY before xinference-local, the supervisor, every worker and every direct actor client; model subprocesses and virtual environments inherit it |
| Leave HTTP clients alone | REST users and API keys are a separate trust domain and must not be given the actor secret just to call inference |
| Restart all peers together | Keyed and unkeyed peers cannot talk, so there is no mixed-mode rolling upgrade and no automatic downgrade; rotating the key needs the same coordinated restart |
| Keep the firewall | Actor ports stay limited to cluster peers, with or without the key |
Source: GHSA-2hj6-h88x-mv4j. The standalone and distributed Compose files in 4.0.1 already pass XOSCAR_AUTH_KEY to all supervisor and worker services. Xinference v4.0.1 release
The advisory states three limits. Anyone holding the key is trusted to run Python in the receiving process, so the key is a cluster-membership secret, not a per-user credential. The authentication does not encrypt traffic and does not stop replay of captured messages. And authenticated GPU transfers, UCX included, stage device buffers in host memory for hashing, which costs CPU and host memory on every transfer. If the key cannot be enabled, the only remaining control is restricting actor ports by firewall, private network or container-network policy. Learning an actor address, for instance from /v1/address, does not bypass auth once it is correctly on. GHSA-2hj6-h88x-mv4j
The public records disagree with each other on scope, which matters if you are matching a scanner finding to a version. The Xoscar advisory lists ”>= 0.1.0, <= 0.12.0” with no patched version, because 0.12.0 with the key unset or empty keeps the legacy transport; the NVD description, which comes from VulnCheck and concerns Xoscar “through 0.11.2”, was published October 13, before either vendor advisory, and the record’s status is Deferred. The 9.8 (CVSS 3.1) and 9.3 (CVSS 4.0) scores on the NVD page are VulnCheck’s, listed as secondary; the Xinference and Xoscar GitHub advisories carry the same 9.3 CVSS 4.0 vector and no CVSS 3.1 score. The CISA ADP container on the CVE record holds an SSVC entry dated October 14 with exploitation “none”, automatable “no”, technical impact “total”; it is a point-in-time entry and the only exploitation signal we found anywhere. No advisory or release note reports exploitation in the wild. The CVE record credits Valentin Lobstein (Chocapikk); the Xinference advisory adds credit to Cyfra Tech Solutions (Roman Arce Brán). NVD, CVE-2026-49950 · CVE.org, CVE-2026-49950 · Xoscar GHSA-mmvj-m246-m9vf · GHSA-2hj6-h88x-mv4j
The two mediums, and why one of them feeds the actor problem
GHSA-h97g-6mc6-66hm is the smaller one on paper, CVSS 4.3, and it is the one we would read next to the actor advisory. Before 4.1.0, /v1/chat/completions could return raw worker exception text, and in a distributed deployment that text can include worker actor addresses and process IDs; a streaming request could send HTTP 200 and then the raw error over SSE. The advisory verified both paths against 4.0.1. The fix returns a fixed generic message for unexpected worker failures at the HTTP and SSE boundary and keeps the diagnostics in server logs; recognized context-limit and validation errors keep their safe fixed messages (HTTP 400, rate limits 429). The advisory demonstrates no code execution, authorization bypass, cross-tenant disclosure or service compromise, and says other endpoints are outside its remediation. The vector’s PR:L says it is reachable by an authenticated client (the advisory adds that unauthenticated clients can reach it when inference authentication is off), which is our reading of the score, and the connection to actor ports is ours as well: an error message that hands out actor addresses is a map to the unauthenticated transport described above, on any cluster without XOSCAR_AUTH_KEY. GHSA-h97g-6mc6-66hm · PR #5767
GHSA-3jw7-r8gq-5ggj, CVSS 5.3, covers two things. POST /v1/models/llm/auto-register accepted a caller-supplied model_path that reached unconfined config and template readers; the disclosure is selected config fields plus an existence and non-empty oracle for files such as config.json, tokenizer_config.json and chat_template.jinja, “not an unrestricted full-file read”. Separately, Flexible launcher names were passed to importlib.import_module, which the advisory says “does not establish command execution”. Reads are now confined to the configured model and cache roots plus XINFERENCE_MODEL_REGISTER_ROOTS, and any extra launcher needs an exact dotted-name entry in the worker-side XINFERENCE_FLEXIBLE_LAUNCHERS list, checked before import; an allowlisted launcher is still trusted worker code. Both are reachable by clients with the relevant API permissions, or by anyone if the API has no authentication, and the fix changes no authentication default. GHSA-3jw7-r8gq-5ggj · PR #5766
Where HTTP auth stops
Put the five together and the lesson applies to any self-hosted inference server, not only Xinference. The REST layer has authentication and scopes, and the fixes for the two mediums are careful about them. But the two paths that give code execution are not REST paths. One is a model loader that treats a YAML file as a program because the upstream library does, and the only thing between a network client and that loader is whether the client can trigger a launch. The other is the actor transport between the server’s own processes, which deserializes whatever arrives and has no notion of a REST user at all. HTTP authentication does not cover the actor ports, which the advisories say outright, and for the loader it only decides who may trigger a launch, not what the launched config is allowed to do. Add that upgrading leaves both controls off, and that an attacker-created admin survives the upgrade, and installing 4.1.0 is where the work starts.
What to check
Version. pip show xinference xoscar on every host, including machines that only run a direct actor client. The targets are 4.1.0 and Xoscar 0.12.0 or later; 4.0.1 has the actor-auth backport and nothing else from this list.
XINFERENCE_TRUST_REMOTE_CODE. Decide per worker. If a worker needs it for a custom CosyVoice source, that worker’s launch and registration endpoints must be reachable only by people you would let run code there, because the flag restores the pre-4.1.0 behavior rather than containing it. Review existing custom registrations before upgrading, since a registered source is relaunched later.
Admin audit. For any deployment with advanced auth, list accounts and API keys and account for each one. If the REST port was ever reachable while the user store was empty, treat the first admin as unproven until you have confirmed it, and use xinference-reset-auth-password if you cannot. Persist the auth database so recreating a container does not reopen the window.
Setup token. On fresh 4.1.0 instances, the first admin cannot be created without the token from the API server’s startup log, so make sure whoever does the setup can read that log.
XOSCAR_AUTH_KEY. env | grep XOSCAR_AUTH_KEY on every peer. Plan the coordinated restart; there is no rolling path. Keep actor ports (9999, 30001 and 30002 in the shipped Compose files) off any network the REST clients share, key or no key, since the key neither encrypts nor prevents replay.
Flexible launchers. Any launcher that is not built in needs its exact dotted name in XINFERENCE_FLEXIBLE_LAUNCHERS after the upgrade; the check runs before import.
We could not verify whether 4.1.0 warns at startup about a missing XOSCAR_AUTH_KEY, what the default actor-port bindings are for Docker or single-node installs, or the PR diffs themselves.
Sources
Xinference releases
- v4.1.0, v4.0.1 — xorbitsai/inference on GitHub
- xinference 4.1.0, xoscar — PyPI
Xinference advisories
- GHSA-2gq8-2q98-6w29, CosyVoice HyperPyYAML code execution, fixed by PR #5765
- GHSA-v43j-w7xm-2vwh, unauthenticated initial admin creation, fixed by PR #5703
- GHSA-3jw7-r8gq-5ggj, auto-registration reads and Flexible launcher imports, fixed by PR #5766
- GHSA-h97g-6mc6-66hm, chat-completion error disclosure, fixed by PR #5767
- GHSA-2hj6-h88x-mv4j, unauthenticated actor transport (CVE-2026-49950), mitigated by PR #5696
Xoscar and CVE-2026-49950
- GHSA-mmvj-m246-m9vf — xorbitsai/xoscar on GitHub
- NVD record — NIST
- CVE.org record — CVE Program
Related S5 Labs coverage: Anthropic’s five exploit chains: the patch checklist
