Red Hat’s tracker entry for CVE-2026-6859 (Bugzilla 2459998) names one hardcoded boolean as the root cause of an arbitrary code execution flaw: trust_remote_code=True, set inside InstructLab instead of left to the person running it. InstructLab is a CLI for chatting with and training open models using custom taxonomy data (instructlab/instructlab), so loading model repositories from Hugging Face is not an edge case in this tool. It is the job. With trust hardcoded on, loading a model from an attacker-controlled repository executes that repository’s custom Python. The qualifier matters: a repository that ships no code files has nothing to execute, and the attack needs Python the attacker controls. As of October 2, 2026 the entry sits in NEW status with an empty Fixed In Version field, more than five months after it was reported on April 21, 2026.
What the Advisory Records
The Bugzilla entry is a Security Response tracker, so it is metadata-dense and prose-light. Its summary line carries the whole finding: “CVE-2026-6859 instructlab: InstructLab: Arbitrary code execution due to hardcoded trust_remote_code=True.” Priority is high, severity is high, the assignee is Product Security, and the bug was reported April 21, 2026 and last modified the next day. Fixed In Version and Last Closed are both empty.
That is Red Hat’s own triage: high severity, high priority, five months in, no fixed release recorded. Understanding why one boolean earns that triage requires leaving the advisory and reading the library it misuses.
What the Hardcoded Flag Bypasses
The flag matters because of transformers’ dynamic module loading path (dynamic_module_utils.py, on main as of a September 22, 2026 commit). When a repository ships custom modeling code, transformers downloads those .py files into a local module cache, resolves their relative imports, and imports them for real: get_class_in_module() builds a module from the cached file with importlib.util.spec_from_file_location() and runs exec_module() on it. The docstring states the consequence without hedging: “Calling this function will execute the code in the module file found locally or downloaded from the Hub. It should therefore only be called on trusted repos.”
None of this is a bug in transformers. Remote code exists so architectures that ship custom Python alongside their weights can load, and the library wraps the mechanism in a gate. resolve_trust_remote_code() treats running that code as the user’s decision, and its behavior when the argument is left unset is precise. If the model has local code available, the resolver silently falls back to it and never asks anything. If the only code is remote, it prints the repository URL and asks “Do you wish to run the custom code? [y/N]” under a 15-second alarm (TIME_OUT_REMOTE_CODE = 15); “y”, “yes” or “1” grants trust, “n”, “no” or an empty answer refuses, and an expired timeout raises a ValueError. After resolution, a repository whose only code is remote and that received no grant raises a ValueError telling the user to pass trust_remote_code=True explicitly.
A caller that hardcodes True skips the prompt, the timeout and both error paths, which is precisely what the CVE names. transformers even leaves a paper trail of intended caution downstream of the gate: when new code files are downloaded it logs a warning to “double-check they do not contain any added malicious code” and suggests pinning a revision so updated code is not pulled in silently. Hardcoding the flag in a tool whose purpose is loading user-specified repositories is the software equivalent of writing AllowUsers * in sshd_config and calling it a feature.
Why picklescan and ModelScan Miss This
Most ML supply-chain scanning is built for pickle deserialization: a malicious .pkl checkpoint embeds executable code in its serialized object graph, and the scanner’s job is to find it before torch.load() runs it. picklescan is exactly that. It scans Pickle files from local paths, directories, URLs, zip archives and whole Hugging Face repositories, and reports dangerous globals, such as the __builtin__ eval import it flags in its README’s example scan of a hostile PyTorch checkpoint. What it inspects inside a repository is the Pickle in the checkpoint.
ModelScan broadens the formats (Pickle plus its dill, joblib and cloudpickle relatives, H5, SavedModel protocol buffers, Keras V3) while keeping the same threat class. Its README defines the problem as malicious code “added to the contents of a model during serialization(saving) before distribution,” and describes its method as reading file contents “one byte at a time just like a string, looking for code signatures that are unsafe.”
The trust_remote_code vector is in neither surface. It is not embedded in a serialized artifact at all. It is plain Python, downloaded during a live load-and-import sequence, shaped like legitimate model architecture code because that is what it claims to be. A scanner keyed on Pickle globals has nothing to key on. A scanner reading serialized model bytes is reading the wrong files. ModelScan’s README also advises users to “scan content from any untrusted source before use”; repository-hosted Python is untrusted content that neither tool’s documented format list covers.
Where a Fix Would Land
The instructlab repository’s README now opens with a community announcement dated September 2, 2025: the project is refactoring “primarily as a framework SDK for model tuning,” with the announcement pointing synthetic data generation at sdg_hub and training at training_hub, both under the Red-Hat-AI-Innovation-Team organization, and encouraging contributors to follow the component projects “in their new homes.”
For patch tracking, that is an awkward substrate. The tracker carrying the CVE records no fixed release: Status NEW, Fixed In Version empty, Last Closed empty, as of October 2, 2026. The component split means there is also no single obvious repository to watch for a patch commit, and the announcement is framed around maintainability rather than security.
A correct fix is small and already modeled in the library. Stop hardcoding the flag and let resolve_trust_remote_code() do its job, with trust as a user decision that defaults to refusal. transformers ships the prompt, the timeout and the error path; the fix is to stop overriding them.
What Operators Can Do Before a Patch
No fix is recorded. Until one is:
Read the repository, not just the weights. The exposure is the .py files that ride along with a model. Review custom modeling code before loading any repository not already trusted, and treat “does this repo ship Python at all?” as the first triage question, since repositories without custom code files have nothing to execute.
Treat a clean scan as silence, not clearance. A picklescan or ModelScan pass over a checkpoint says nothing about remote code. The attack is not in the checkpoint.
Scope the process. Code that runs through this path executes with whatever privileges the loading process has. A container or dedicated account with minimal host access bounds the damage if a hostile repository is loaded anyway.
Watch the tracker. Bugzilla 2459998 is where Red Hat will record a fixed version; the field was still empty on October 2, 2026.
The implication runs past InstructLab. Any tool that calls transformers’ loading APIs with trust_remote_code=True on user-supplied repositories has the same exposure, whatever scanner stack runs beside it. The parameter is a code-execution gate. transformers built the gate with a prompt, a timeout and a default of refusal, and the vulnerability class is a caller that props it open without telling the user.
Join the discussion
Share a useful perspective or ask a question about this article.