// threat brief

MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can run arbitrary code

CVSS
8.8 HIGH
CISA KEV
Not listed
Weakness
CWE-502

PlainCVE Team · Published 2026-09-30 · AI-assisted · Press brief ↓

AI review 2026-09-30 (not human-reviewed)Command tests: none yetReproduced: not yetVerification record ↓

MLflow's statsmodels flavor ignores MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False, so teams that blocked pickle can still run attacker code from a tampered model.

Who is affectedOrganizations on MLflow 2.1.0 through 3.14.0 that set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False expecting MLflow to refuse pickle-based models, and that load models from a store others can write to; in these versions the statsmodels flavor ignores the setting, whether loaded through mlflow.pyfunc.load_model() or mlflow.statsmodels.load_model(). If you never set the variable, MLflow's default (True) already loads pickle by design; that is not caused by this flaw, but the risk of loading untrusted models is there regardless.
What happensIf an attacker can place a model where you get models from and your code loads it, the attacker's code runs with the privileges of the loading process, even if you set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False.
What to do nowUpgrade MLflow to 3.15.0 or later (CERT/CC says to upgrade immediately). PlainCVE also suggests setting MLFLOW_ALLOW_PICKLE_DESERIALIZATION to False (neither MLflow nor CERT/CC recommends this): the variable defaults to True, and without setting it MLflow still loads pickle after upgrading; once set, other flavors that need pickle and have this check will also refuse to load. Per fix PR #24686, the check does not run in the Databricks runtime or model serving environments. On any version, load models only from trusted sources.
Affected versions2.1.0 through 3.14.0 (CVE description); MLflow's GHSA lists 2.1.0 and later as affected with 3.15.0 patched, and the CVE record's structured fields list 2.1 up to, but not including, 3.15.0. Only environments that set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False are affected
Fixed versions3.15.0 or later
CVSS vector
Show full vectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Timeline
  • First public 2026-07-27

Blue team playbook

Check, fix / mitigate, respond, harden. Matching the affected versions does not mean you were compromised, and a check that finds nothing does not prove you are safe; each item says what it can and cannot show. Tagged steps point to where the attack flow below can be stopped.

DETECTCheckAm I affected? Any signs of compromise?
  1. 01Check your MLflow version

    2.1.0 through 3.14.0 are affected (MLflow's GHSA lists 3.15.0 as patched). Also consider whether you load models from a store others can write to.

    Read-only check
    pip show mlflow | grep -i '^version'
  2. 02Check whether the pickle-blocking setting is in effect

    This flaw only affects environments that set MLFLOW_ALLOW_PICKLE_DESERIALIZATION to False; in MLflow's source code the variable defaults to True. Run this in the same Python environment and with the same environment variables as the process that actually loads models; only an output of False means pickle loading is forbidden.

    Read-only check
    python -c "from mlflow.environment_variables import MLFLOW_ALLOW_PICKLE_DESERIALIZATION as v; print(v.get())"
  3. 03Find models that name the statsmodels flavor

    If your team does not normally use statsmodels, models whose MLmodel file names mlflow.statsmodels as the loader are worth flagging for review. This is PlainCVE's suggestion, not MLflow guidance; the command only works for artifact stores on a local file system.

    Read-only check
    grep -rl "mlflow.statsmodels" /path/to/artifact-store --include=MLmodel
MITIGATEFix / mitigatePatch; block it if you cannot patch yet
  1. 01Upgrade to 3.15.0 or later

    MLflow's official 3.15.0 release notes include the change adding the pickle guard to the statsmodels flavor (PR #24686). Per the v3.15.0 source code, the new check blocks only when MLFLOW_ALLOW_PICKLE_DESERIALIZATION is False and the process is not in the Databricks runtime or a Databricks model serving environment. Upgrading alone does not change the default behavior; blocking pickle requires the next item (PlainCVE's suggestion).

    Changes your environment
    pip install -U "mlflow>=3.15.0"
  2. 02After upgrading, set MLFLOW_ALLOW_PICKLE_DESERIALIZATION to False (PlainCVE's suggestion)

    The variable defaults to True (v3.15.0 source code), meaning pickle loading is allowed by default; only when it is False does the statsmodels flavor in 3.15.0 and later refuse pickle models. Set it in the environment of the processes that actually load models (serving, batch jobs, notebooks); the command below only applies to the current shell session. Once set, other flavors that need pickle and have this check will also refuse to load; the workaround MLflow's error message offers is setting it back to true. This is PlainCVE's suggestion: neither MLflow nor CERT/CC recommends that users set it, and fix PR #24686 protects users who have already set it to False.

    Configuration example
    export MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False
  3. 03Can't upgrade yet: accept models only from trusted sources

    CERT/CC says the attack requires write access to a place users get models from, so allowing only trusted sources to write or register models until you patch lowers the risk (PlainCVE's suggestion based on that precondition). Note: on older versions, setting MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False alone does not stop this. The sources give no other workaround for the statsmodels flaw itself.

RESPONDRespondIf you find signs of compromise
  1. 01If a suspicious model was loaded, treat the host as compromised

    The code runs with the loading process's privileges, so any credentials and data that process could reach may be exposed. This is PlainCVE's suggestion; the sources give no incident response guidance.

HARDENHardenPrevent the next one
  1. 01Turn on authentication for the MLflow server

    According to the GHSA text, default deployments without the basic-auth app allow uploads with no credentials. Turning on login and limiting write access is PlainCVE's suggestion.

  2. 02Load models only from trusted sources

    In environments that have not set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False, MLflow loads pickle by default, so loading an untrusted model can already run code hidden in it, and upgrading does not change that. The setting is also not yet applied to every flavor: CERT/CC says the dspy flavor has a similar bypass, and only a later MLflow pull request (#25566, merged 2026-09-03) added the same protection to the mlflow.shap flavor. This is PlainCVE's suggestion.

  3. 03Run model loaders with least privilege

    If a malicious model does get loaded, the damage stays limited. This is PlainCVE's suggestion.

Full remediation steps and notes
  1. Upgrade. pip install -U "mlflow>=3.15.0" in every environment that loads models (serving, batch jobs, notebooks), not only the tracking server.
  2. After upgrading, set MLFLOW_ALLOW_PICKLE_DESERIALIZATION to False (PlainCVE’s suggestion). Neither MLflow nor CERT/CC recommends that users set it; the fix protects users who have already set it to False. Once set, other flavors that need pickle and have this check will also refuse to load. The variable defaults to True, and the check added by the fix, PR #24686, only blocks when it is False; without setting it, the statsmodels flavor still loads pickle after upgrading. Set it in the environment of the processes that actually load models. Per PR #24686, the check is skipped in the Databricks runtime and Databricks model serving environments. On older versions, setting the variable alone does not stop the statsmodels flavor.
  3. Load models only from trusted sources. This is the baseline on any version and setting; where pickle is not forbidden, loading an untrusted model can already run code hidden in it. The sources give no workaround for the statsmodels flaw itself; CERT/CC says to upgrade immediately. The CERT/CC advice to avoid the dspy flavor covers a different dspy flaw and does not help here. CERT/CC says the attack requires write access to a place you get models from, so allowing only trusted sources to write or register models lowers the risk (PlainCVE’s suggestion).

Attack flow

Read left to right: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Click an icon for details.

Read top to bottom: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Tap an icon for details.

MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can run arbitrary code: 1. The attacker places a tampered model in a model store → 2. The model's config file names the statsmodels flavor as its loader → 3. The victim's process loads the model with mlflow.pyfunc.load_model() → 4. The statsmodels _load_model() never checks the pickle-blocking setting → 5. The attacker's code runs with the loading process's privilegesCVE-2026-96804 · MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can runarbitrary codeAttackerYour systemThe attacker places a tampered model in a model store — This requires write access to a place users get MLflow models from (such as an artifact store, the storage that holds model files). According to the GHSA text, default MLflow deployments have login switched off, so uploads need no credentials. 1The attackerplaces a tamperedmodel in a modelstoreThe model's config file names the statsmodels flavor as its loader — MLmodel is the config file shipped with every model; it says which format (flavor) should be used to load it. 2The model's configfile names thestatsmodels flavoras its loaderThe victim's process loads the model with mlflow.pyfunc.load_model() — For example, a model-serving service or batch inference job picks up the model. According to the MLflow 3.14.0 source code, calling mlflow.statsmodels.load_model() directly reaches the same _load_model(). 3The victim'sprocess loads themodel withmlflow.pyfunc.load_model()The statsmodels _load_model() never checks the pickle-blocking setting — The statsmodels flavor saves models with pickle internally. MLflow allows pickle loading by default; operators can forbid it with MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False, but older versions of the statsmodels flavor ignore that setting and silently load it anyway. 4The statsmodels_load_model()never checks thepickle-blockin…The attacker's code runs with the loading process's privileges — What it can do depends on the data, keys and systems that process can reach. 5The attacker'scode runs with theloading process'sprivilegesAttack pathCan be stopped herePlainCVE · plaincve.date/en/vulns/cve-2026-96804-mlflow-statsmodels-pickle-bypass · CC BY 4.0
MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can run arbitrary code: 1. The attacker places a tampered model in a model store → 2. The model's config file names the statsmodels flavor as its loader → 3. The victim's process loads the model with mlflow.pyfunc.load_model() → 4. The statsmodels _load_model() never checks the pickle-blocking setting → 5. The attacker's code runs with the loading process's privilegesCVE-2026-96804 · MLflow statsmodelsflavor ignores the pickle safety switch:loading a crafted model can runarbitrary codeThe attacker places a tampered model in a model store — This requires write access to a place users get MLflow models from (such as an artifact store, the storage that holds model files). According to the GHSA text, default MLflow deployments have login switched off, so uploads need no credentials. 1AttackerThe attacker places a tamperedmodel in a model storeThe model's config file names the statsmodels flavor as its loader — MLmodel is the config file shipped with every model; it says which format (flavor) should be used to load it. 2AttackerThe model's config file namesthe statsmodels flavor as itsloaderThe victim's process loads the model with mlflow.pyfunc.load_model() — For example, a model-serving service or batch inference job picks up the model. According to the MLflow 3.14.0 source code, calling mlflow.statsmodels.load_model() directly reaches the same _load_model(). 3Your systemThe victim's process loads themodel withmlflow.pyfunc.load_model()The statsmodels _load_model() never checks the pickle-blocking setting — The statsmodels flavor saves models with pickle internally. MLflow allows pickle loading by default; operators can forbid it with MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False, but older versions of the statsmodels flavor ignore that setting and silently load it anyway. 4Your systemThe statsmodels _load_model()never checks thepickle-blocking settingThe attacker's code runs with the loading process's privileges — What it can do depends on the data, keys and systems that process can reach. 5AttackerThe attacker's code runs withthe loading process's privilegesAttack pathCan be stopped herePlainCVE · CC BY 4.0plaincve.date/en/vulns/cve-2026-96804-mlflow-statsmodels-pickle-bypass
Free to use in reporting and teaching under CC BY 4.0. Attribution is already on the image.
  1. Attacker

    The attacker places a tampered model in a model store

    This requires write access to a place users get MLflow models from (such as an artifact store, the storage that holds model files). According to the GHSA text, default MLflow deployments have login switched off, so uploads need no credentials.

    Defense: Allow only trusted sources to write or register models; turn on authentication for the MLflow server.

  2. Attacker

    The model's config file names the statsmodels flavor as its loader

    MLmodel is the config file shipped with every model; it says which format (flavor) should be used to load it.

    Defense: Flag models in the store that name mlflow.statsmodels when your team does not normally use that flavor.

  3. Your system

    The victim's process loads the model with mlflow.pyfunc.load_model()

    For example, a model-serving service or batch inference job picks up the model. According to the MLflow 3.14.0 source code, calling mlflow.statsmodels.load_model() directly reaches the same _load_model().

  4. Your system

    The statsmodels _load_model() never checks the pickle-blocking setting

    The statsmodels flavor saves models with pickle internally. MLflow allows pickle loading by default; operators can forbid it with MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False, but older versions of the statsmodels flavor ignore that setting and silently load it anyway.

    Defense: Upgrade to 3.15.0 or later; PlainCVE also suggests setting MLFLOW_ALLOW_PICKLE_DESERIALIZATION to False (it defaults to True, which blocks nothing); per fix PR

  5. Attacker

    The attacker's code runs with the loading process's privileges

    What it can do depends on the data, keys and systems that process can reach.

    Defense: Run model-loading processes with least privilege.

Who is affected

ConditionAffected?
MLflow 2.1.0 through 3.14.0 with MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False set, loading models from a store others can write to (mlflow.pyfunc.load_model() or mlflow.statsmodels.load_model())Affected: the statsmodels flavor ignores the setting
MLflow 3.15.0 or later with MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False setFixed (the check is skipped in the Databricks runtime and model serving environments)
Any version with the variable unset (default True) or set to TrueNot this flaw: MLflow loads pickle by design, so loading an untrusted model can run code hidden in it
MLflow before 2.1.0MLflow’s GHSA and the CVE record both start the affected range at 2.1.0

At its core this flaw bypasses a setting users turn on themselves. According to MLflow’s source code, MLFLOW_ALLOW_PICKLE_DESERIALIZATION defaults to True, meaning pickle loading is allowed by default; the CVE record, CERT/CC and MLflow’s GHSA all describe the statsmodels flavor loading pickle anyway after users set it to False.

The range is worded slightly differently: the CVE description says “2.1.0 to 3.14.0”; the CVE record’s structured fields say from 2.1 up to, but not including, 3.15.0; MLflow’s GHSA says 2.1.0 and later are affected, with 3.15.0 patched. The CERT/CC note says the flaw was confirmed against MLflow 3.12.0.

An attack generally needs all of these: you have set MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False; the attacker can write to a place you get models from (such as an artifact store, the storage that holds model files); the model’s MLmodel config file names the statsmodels flavor as its loader; and your code loads it. The CERT/CC note describes the attack path through mlflow.pyfunc.load_model(); according to the MLflow 3.14.0 source code (mlflow/statsmodels/init.py), both _load_pyfunc(), which pyfunc loading calls, and a direct call to mlflow.statsmodels.load_model() reach the same unchecked _load_model(), so both ways of loading are affected. According to the GHSA text, default MLflow deployments without the basic-auth app have login switched off, so uploads need no credentials.

How it works

MLflow uses “flavors” to save and load models built with different libraries. According to MLflow’s documentation, the statsmodels flavor uses pickle internally to save models. Pickle is Python’s format for saving objects, and loading an untrusted pickle file can run code hidden inside it. This class of problem is called unsafe deserialization (CWE-502).

For this reason MLflow offers an environment variable (a setting a program reads at startup), MLFLOW_ALLOW_PICKLE_DESERIALIZATION. It defaults to True, which allows pickle loading; setting it to False forbids it. The problem is that the statsmodels flavor’s _load_model() never checked this setting at all. Operators believed pickle risk was blocked, but this flavor silently loaded pickle anyway. The result: a remote attacker who supplies a crafted model may get arbitrary code to run, with the privileges of the loading process.

The flawed approach (conceptual illustration, not the original source code):

Show code example(python)
def _load_model(path):
    # Never checks the safety switch; reads the pickle directly
    return read_pickle(path)

The fixed approach:

Show code example(python)
def _load_model(path):
    if not pickle_deserialization_allowed():
        raise SecurityError("pickle loading is disabled")
    return read_pickle(path)

Timeline

DateEvent
2026-07-27MLflow publishes security advisory GHSA-gqvg-gmmx-x4hm (listed as a reference in CERT/CC note VU#369093), the earliest public record of this flaw
2026-07-31MLflow v3.15.0 released with the fix (PR #24686). Date per the GitHub releases API and PyPI upload records
2026-09-01OSV publishes GHSA-gqvg-gmmx-x4hm
2026-09-16CERT/CC publishes note VU#369093
2026-09-23CVE published; CISA’s assessment records no known exploitation
2026-09-25Not in CISA KEV as of this date

Further reading

  • The CVE mapping is disputed. The original CERT/CC note VU#369093 (not only a republished copy) describes the dspy flaw first and the statsmodels flaw second, then says they are CVE-2026-96804 and CVE-2026-96775 “respectively”, which read literally makes this CVE the dspy flaw. The official CVE record maps CVE-2026-96804 to statsmodels, and Strix lists CVE-2026-96775 as the dspy flaw. CERT/CC is also the CNA that published this CVE, so its note and its own CVE record disagree. This page follows the CVE record in mapping CVE-2026-96804 to statsmodels.
  • The link to MLflow’s advisory. CERT/CC note VU#369093 lists MLflow’s security advisory GHSA-gqvg-gmmx-x4hm as a reference, and that advisory describes exactly this statsmodels pickle-control bypass. The CVE’s own GitHub entry is a separate, unreviewed advisory, GHSA-2qmw-5xhm-qq5w. This page uses the earlier GHSA-gqvg-gmmx-x4hm publication date, 2026-07-27, as the first disclosure date; the CVE was published on 2026-09-23.
  • Scoring differences. In the CVE record, CISA rates it 8.8 with a vector assuming low privileges and no user action; GHSA (on OSV and GitLab) also gives 8.8 but assumes no privileges and user action. NVD’s status is “Deferred”, so NVD has done no analysis of its own.
  • Exploitation. Not in CISA KEV; CISA’s assessment says no known exploitation, not automatable, total technical impact. On a public proof-of-concept, TheHackerWire says none is confirmed; another third-party site claims one exists, but its page contains runnable attack code, so this page does not cite it. No source offers evidence on exploitation before a fix existed.
  • Coordination. The CERT/CC note says MLflow could not be reached to coordinate these vulnerabilities.
  • Related flaws. CERT/CC says a similar bypass in the dspy flavor had no fix yet. A later MLflow pull request, #25566 (merged 2026-09-03), used the statsmodels guard as the pattern for adding the same protection to the mlflow.shap flavor; that PR changes only the shap flavor.

Verification Checked item by item against sources by AI under our review rules, all passed; not human-reviewed and not yet reproduced in our lab

AI review2026-09-30 · review rules

Verification records describe the environment and the result only, never reproduction steps or code that could attack other people’s systems. See our policy.

Sources

  1. CVE / NVD / OSVCVE-2026-96804 Record (CVE API) · CVE Program, 2026-09-23 · accessed 2026-09-25
  2. CVE / NVD / OSVNVD API - CVE-2026-96804 · NIST · accessed 2026-09-25
  3. AdvisoryGHSA-gqvg-gmmx-x4hm: MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False safety control bypassed by mlflow.statsmodels flavor · MLflow (GitHub), 2026-07-27 · accessed 2026-09-28
  4. Patch / releaseMLflow v3.15.0 release · MLflow (GitHub), 2026-07-31 · accessed 2026-09-25
  5. Patch / releaseMLflow pull request #24686 · MLflow (GitHub), 2026-07-27 · accessed 2026-09-28
    The fix; the new check does not run in the Databricks runtime or Databricks model serving environments
  6. Othermlflow 3.15.0 (PyPI JSON API) · PyPI, 2026-07-31 · accessed 2026-09-28
  7. Patch / releaseMLflow pull request #25566 · MLflow (GitHub), 2026-09-03 · accessed 2026-09-28
  8. Vendormlflow.statsmodels documentation · MLflow · accessed 2026-09-25
  9. AdvisoryGHSA-gqvg-gmmx-x4hm (GitLab Advisory Database) · GitLab · accessed 2026-09-25
  10. AdvisoryGHSA-gqvg-gmmx-x4hm (OSV) · OSV, 2026-09-01 · accessed 2026-09-25
  11. AdvisoryVU#369093: MLflow dspy and statsmodels flavors bypass pickle deserialization control · CERT/CC, 2026-09-16 · accessed 2026-09-28
  12. Vendormlflow/statsmodels/__init__.py (v3.14.0) · MLflow (GitHub) · accessed 2026-09-28
    v3.14.0 source: both load_model() and _load_pyfunc() call _load_model()
  13. Vendormlflow/environment_variables.py (v3.15.0) · MLflow (GitHub) · accessed 2026-09-28
    MLFLOW_ALLOW_PICKLE_DESERIALIZATION is a boolean environment variable with a default of True (also True in v3.14.0)
  14. Vendormlflow/statsmodels/__init__.py (v3.15.0) · MLflow (GitHub) · accessed 2026-09-28
    v3.15.0 source: _load_model() refuses to load only when MLFLOW_ALLOW_PICKLE_DESERIALIZATION is False and the process is not in the Databricks runtime or model serving environment
  15. OtherCVE-2026-96804 · Strix · accessed 2026-09-25
  16. NewsCVE-2026-96804 · TheHackerWire · accessed 2026-09-25

Press brief

In one sentence

MLflow is a widely used open-source machine learning platform. It loads pickle-based models by default, and operators can turn on a safety switch that forbids this, but its statsmodels model format never checked that switch, so even with pickle forbidden a tampered model file could run arbitrary code when loaded. MLflow added the check in version 3.15.0, but it only protects users who set the switch to forbid pickle. As of September 25, 2026, the flaw is not in CISA's Known Exploited Vulnerabilities catalog, and no source reports exploitation in the wild.

Key facts

Severity
CVSS 3.1 8.8 (CISA ADP, CVE record) cveawg.mitre.org
Fixed version
3.15.0 github.com
Affected versions
2.1.0 up to, but not including, 3.15.0 (MLflow GHSA) github.com
MLflow advisory (listed as a reference in the CERT/CC note)
GHSA-gqvg-gmmx-x4hm, 2026-07-27 github.com
CVE published
2026-09-23 cveawg.mitre.org

Confirmed

  • MLflow's statsmodels flavor in 2.1.0 through 3.14.0 does not apply the MLFLOW_ALLOW_PICKLE_DESERIALIZATION=False control on load (CVE record).
  • MLflow's official 3.15.0 release notes include the change adding the pickle guard to the statsmodels flavor; per the v3.15.0 source code, the guard blocks only when MLFLOW_ALLOW_PICKLE_DESERIALIZATION is set to False, and the variable defaults to True.
  • Not in CISA KEV as of 2026-09-25; CISA's 2026-09-23 assessment records no known exploitation.

Unconfirmed / disputed

  • The original CERT/CC note VU#369093, read literally, maps CVE-2026-96804 to the dspy flaw, which disagrees with the CVE record; this page follows the CVE record.
  • Sources disagree on required privileges: CISA says low privileges and no user action; GHSA says no privileges but user action.
  • Whether a public proof-of-concept exists: TheHackerWire says none is confirmed; another third-party site claims one exists, but its page contains runnable attack code, so this page does not cite it.
  • No source offers evidence on whether it was exploited before a fix existed.

Quotable line

Operators thought they had locked the door, but one side entrance never had a lock at all.

Images

Download the share image (PNG) · Attack flow diagram (downloadable)

Please credit "PlainCVE" and link to this page. Full citation format is under "How to cite" below. Found a factual error? Report it.

How to cite this page

This article is CC BY 4.0. Please keep the attribution and link when republishing.

PlainCVE Team (2026). "MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can run arbitrary code". PlainCVE. https://plaincve.date/en/vulns/cve-2026-96804-mlflow-statsmodels-pickle-bypass (accessed YYYY-MM-DD)
BibTeX
@misc{cve202696804mlflowstatsmodelspicklebypass2026,
  title  = {MLflow statsmodels flavor ignores the pickle safety switch: loading a crafted model can run arbitrary code},
  author = {PlainCVE Team},
  year   = {2026},
  howpublished = {PlainCVE},
  url    = {https://plaincve.date/en/vulns/cve-2026-96804-mlflow-statsmodels-pickle-bypass},
  note   = {Updated 2026-09-30}
}