← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-4372 · CWE-1066 · Disclosed 2026-05-24

A critical remote code execution vulnerability exists in all versions of the HuggingFace transformers…

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a booby-trapped package on the loading dock, not a burglar kicking in your front door

CVE-2026-4372 is a model-loading RCE in huggingface/transformers where a malicious model config.json can smuggle an internal field such as _attn_implementation_internal that points model loading toward attacker-controlled code. NVD currently says all versions before 5.3.0 are affected, while multiple secondary reports narrow practical exploitability to the newer 4.56.0 through 5.2.x line and sometimes mention the optional kernels path; absent a vendor advisory clarifying the scope, treat <5.3.0 as the safe operational boundary.

The vendor's 7.8 HIGH is directionally fair on raw impact but too generous on reachable population. This is not an unauthenticated network service bug; the attacker needs a victim workflow that fetches or opens an untrusted model, which means exposure is concentrated in ML workstations, CI jobs, GPU servers, and automated evaluation pipelines rather than your whole estate. The bypass of trust_remote_code=False is the amplifier, but the need to load hostile content is still the main friction, so this lands as MEDIUM for broad enterprise patch triage.

"Serious code exec if you load untrusted models, but this is a supply-chain trap, not an internet-wide worm hole."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Seed a malicious model repo on the Hub

The attacker publishes or tampers with a model repository so its config.json carries a hostile internal kernel-selection value such as _attn_implementation_internal. The weaponized tool here is the Hugging Face Hub itself as the distribution channel, with the payload hidden in a normal-looking model artifact rather than a standalone executable.
Conditions required:
  • Attacker can publish or socially engineer use of a model repository
  • Victim organization allows staff or automation to pull models from public or weakly governed sources
Where this breaks in practice:
  • Private allowlists of trusted publishers cut this off early
  • Many enterprises do not let production jobs pull arbitrary public models
  • The attacker still needs visibility or lure value so someone actually chooses the model
Detection/coverage: Traditional vulnerability scanners will not see this step. This is better caught by Hub governance, repository allowlisting, and content inspection of config.json for suspicious internal fields.
STEP 02

Victim loads the model in a normal workflow

A user or pipeline calls a standard loader such as AutoModelForCausalLM.from_pretrained() against the malicious repo. The important operational twist is that this can occur during routine benchmarking, fine-tuning, notebook experimentation, or automated model evaluation, so the exploit rides on expected developer behavior.
Conditions required:
  • A vulnerable transformers version is installed
  • A model-loading workflow fetches the attacker-controlled repo
  • User interaction or pipeline execution occurs
Where this breaks in practice:
  • Requires a real model-load event, not just package presence
  • Some environments pin models internally and never hit public Hub content
  • Air-gapped or mirrored environments reduce spontaneous exposure
Detection/coverage: EDR can sometimes catch the downstream child process or Python execution, but there is usually no signature-level pre-exploit visibility from package scanners alone.
STEP 03

Internal field bypasses expected safety assumptions

The vulnerable code path deserializes unsafe config attributes and allows kernel loading logic that maintainers later restricted in commit a7f8e7f. The weaponized component is src/transformers/integrations/hub_kernels.py, where the fix explicitly limits acceptable kernel repos and blocks deserialization of problematic internal fields.
Conditions required:
  • The runtime honors the malicious internal config field
  • The vulnerable integration path is reachable in the installed build
Where this breaks in practice:
  • If the runtime never reaches kernel-loading logic, practical exploitability may be lower
  • Reports disagree on whether older versions or only newer branches are truly weaponizable
Detection/coverage: SBOM and package-version checks can identify vulnerable versions; file-content scans for _attn_implementation_internal or _experts_implementation_internal in cached Hub configs add better signal.
STEP 04

Arbitrary code runs with the loader's OS privileges

Once triggered, attacker code executes in the context of the Python process running the model load. On ML hosts that often means access to cloud credentials, API tokens, SSH material, datasets, source code, and high-value GPU infrastructure; the blast radius is host-level or job-level, not inherently domain-wide.
Conditions required:
  • Successful code retrieval and execution from the malicious repo
  • Victim process has access to secrets or adjacent infrastructure
Where this breaks in practice:
  • Least-privilege service accounts and ephemeral runners can contain impact
  • Container sandboxes and egress controls can limit follow-on actions
  • This does not automatically grant enterprise-wide control
Detection/coverage: EDR, runtime policy engines, and cloud workload protection may catch post-exploitation actions such as token theft, shell spawn, curl/wget, or anomalous outbound connections.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo confirmed in-the-wild exploitation found in the sources reviewed, and the user-provided intel says KEV listed: No.
KEV statusNot present in CISA KEV as of the reviewed catalog page; this matches the user intel.
PoC / exploit pathA public exploit path is effectively embedded in the advisory narrative itself: malicious config.json plus AutoModelForCausalLM.from_pretrained(). NVD references a Huntr advisory and the patch commit; that is enough for competent operators to reproduce quickly.
EPSS0.00089 from the user intel, which is very low and consistent with a niche, workflow-dependent package exploit rather than mass internet exploitation.
CVSS vector reality checkCVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H correctly signals user interaction and a non-network attack path. In plain English: devastating once triggered, but not directly wormable over the internet.
Affected versionsNVD says all versions before 5.3.0. Secondary reporting suggests the weaponized path may be concentrated in 4.56.0 through 5.2.x and in some writeups only when the optional kernels path is present; treat that narrower range as an inference from secondary sources, not the authoritative floor.
Fixed version5.3.0 according to NVD and multiple downstream databases. The referenced patch commit is a7f8e7ff37d87d1a1a0c8cf607971c607741452f.
Exposure / scanning realityShodan/Censys/FOFA/GreyNoise are poor lenses here because this is a client/library flaw, not an internet-exposed daemon with a banner to fingerprint. Exposure has to be measured through asset inventory, SBOM, package managers, containers, notebooks, and CI runners.
Disclosure timelineUser intel gives 2026-05-24 disclosure. NVD change history shows the CVE was received from huntr.dev on 2026-05-24 and NIST added enrichment on 2026-06-04.
Researcher / reporting orgThe CNA on NVD is huntr.dev. A precise individual researcher name was not recoverable from the browsed Huntr page rendering.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (6.2/10)

The decisive factor is attacker position: this bug requires the victim to load a malicious model or config into a vulnerable ML workflow, so it is a supply-chain execution path rather than an unauthenticated remote service exploit. That sharply narrows the exposed population even though the host-level impact after trigger is severe.

HIGH Host impact is full code execution in the loader context once triggered
MEDIUM Practical affected version range beyond NVD's `<5.3.0` boundary
HIGH No current KEV or broad exploitation pressure

Why this verdict

  • Downgrade for attacker position: this is not unauthenticated remote against a listening service; it requires a victim model-load event, which implies prior lure success or a permissive automation pipeline.
  • Downgrade for exposed population: only hosts that both run transformers and ingest untrusted model repos are materially at risk. On a 10,000-host estate, that is usually a small ML subset, not the fleet.
  • Upgrade from LOW because trust assumptions are broken: the bypass of trust_remote_code=False means normal defensive habits around 'safe model loading' are not sufficient, so impacted ML platforms deserve real urgency.
  • Downgrade for current threat intel: no KEV listing, no confirmed active exploitation, and very low EPSS mean the external exploitation pressure is currently weak.
  • Keep it above backlog noise because blast radius is rich: the vulnerable hosts are often GPU servers, CI runners, or data-science workstations with secrets, cloud creds, source code, and proprietary datasets.

Why not higher?

It is not higher because the exploit chain is gated by user or pipeline behavior: somebody has to load a malicious model, and many enterprises already restrict public model intake. There is also no strong evidence yet of active exploitation or mass scanning pressure, which matters when deciding what jumps the queue for an enterprise patch calendar.

Why not lower?

It is not lower because the end state is still arbitrary code execution on high-value AI infrastructure under routine documented usage. The trust_remote_code bypass removes a safety assumption many teams were relying on, so affected ML assets should not be treated as mere hygiene.

05 · Compensating Control

What to do — in priority order.

  1. Block untrusted model sources — Enforce publisher allowlists or internal mirrors for Hugging Face content and stop direct pulls from arbitrary public repos. For a MEDIUM verdict there is no mitigation SLA, but if these systems ingest public models today, deploy this control immediately as risk reduction while you move toward the patch.
  2. Scan caches for hostile internal fields — Search downloaded or cached model config.json files for _attn_implementation_internal and _experts_implementation_internal to find likely exposure or tampering. There is no mitigation SLA — go straight to the 365-day remediation window, but do the scan early because it can uncover already-seeded artifacts.
  3. Constrain model-loading runtimes — Run notebooks, CI jobs, and model-eval workers with least-privilege identities, restricted egress, read-only filesystems where possible, and short-lived credentials. This does not remove the bug, but it limits the damage if code execution fires before you fully remediate.
  4. Instrument EDR on GPU and ML nodes — Make sure the hosts that actually load models have runtime telemetry and alerting for shell spawns, network fetches, and token access from Python processes. This is especially useful on research and evaluation infrastructure where package scanners alone have little visibility.
What doesn't work
  • trust_remote_code=False by itself does not solve this; the vulnerability explicitly abuses a path that bypasses that safety expectation.
  • Perimeter network scanning does not help much because this is not mainly an internet-exposed service fingerprinting problem.
  • Patching only developer laptops while leaving CI runners and GPU workers untouched misses the systems most likely to auto-load models at scale.
06 · Verification

Crowdsourced verification payload.

Run this on the target host, container image, notebook base image, or CI runner that may have transformers installed. Invoke it with python3 verify_cve_2026_4372.py or point it at an alternate cache root with HF_HOME=/srv/hf-cache python3 verify_cve_2026_4372.py; no admin rights are required, but the script only inspects locations the current user can read.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
"""
verify_cve_2026_4372.py

Checks for vulnerable Hugging Face transformers versions and scans common
Hugging Face cache locations for suspicious internal config fields related to
CVE-2026-4372.

Outputs one of:
  VULNERABLE - vulnerable version present and/or suspicious cached configs found
  PATCHED    - transformers installed at >= 5.3.0 and no suspicious configs found
  UNKNOWN    - transformers not installed, version unreadable, or no readable evidence

Exit codes:
  0 = PATCHED
  1 = VULNERABLE
  2 = UNKNOWN
"""

import json
import os
import re
import sys
from pathlib import Path

TARGET_VERSION = (5, 3, 0)
SUSPICIOUS_KEYS = {"_attn_implementation_internal", "_experts_implementation_internal"}


def parse_version(v):
    nums = re.findall(r"\d+", str(v))
    if len(nums) < 3:
        nums += ["0"] * (3 - len(nums))
    try:
        return tuple(int(x) for x in nums[:3])
    except Exception:
        return None


def get_transformers_version():
    try:
        try:
            from importlib.metadata import version, PackageNotFoundError
        except ImportError:
            from importlib_metadata import version, PackageNotFoundError  # type: ignore
        try:
            return version("transformers")
        except PackageNotFoundError:
            return None
    except Exception:
        return None


def candidate_cache_roots():
    roots = []
    env_hf_home = os.environ.get("HF_HOME")
    env_hub_cache = os.environ.get("HUGGINGFACE_HUB_CACHE")
    home = Path.home()

    if env_hub_cache:
        roots.append(Path(env_hub_cache))
    if env_hf_home:
        roots.append(Path(env_hf_home) / "hub")

    roots.extend([
        home / ".cache" / "huggingface" / "hub",
        home / ".cache" / "huggingface",
        Path("/root/.cache/huggingface/hub"),
        Path("/opt/huggingface/hub"),
        Path("/var/cache/huggingface/hub"),
    ])

    # de-duplicate while preserving order
    seen = set()
    out = []
    for r in roots:
        s = str(r)
        if s not in seen:
            seen.add(s)
            out.append(r)
    return out


def scan_for_suspicious_configs():
    hits = []
    scanned_files = 0
    for root in candidate_cache_roots():
        if not root.exists():
            continue
        for path in root.rglob("config.json"):
            try:
                scanned_files += 1
                with path.open("r", encoding="utf-8", errors="ignore") as f:
                    data = json.load(f)
                bad = sorted(SUSPICIOUS_KEYS.intersection(set(data.keys())))
                if bad:
                    hits.append({"path": str(path), "keys": bad})
            except Exception:
                continue
    return scanned_files, hits


def main():
    version_str = get_transformers_version()
    version_tuple = parse_version(version_str) if version_str else None
    scanned_files, hits = scan_for_suspicious_configs()

    print("=== CVE-2026-4372 verification ===")
    print(f"transformers_version={version_str}")
    print(f"scanned_config_files={scanned_files}")
    print(f"suspicious_config_hits={len(hits)}")
    for hit in hits[:20]:
        print(f"hit={hit['path']} keys={','.join(hit['keys'])}")
    if len(hits) > 20:
        print(f"note=truncated_output total_hits={len(hits)}")

    # Decision logic
    if version_tuple is None and scanned_files == 0:
        print("UNKNOWN")
        return 2

    if version_tuple is not None and version_tuple < TARGET_VERSION:
        print("VULNERABLE")
        return 1

    if hits:
        # Even if patched now, suspicious cached artifacts suggest prior exposure risk.
        print("VULNERABLE")
        return 1

    if version_tuple is not None and version_tuple >= TARGET_VERSION:
        print("PATCHED")
        return 0

    print("UNKNOWN")
    return 2


if __name__ == "__main__":
    sys.exit(main())
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, inventory everywhere transformers runs: notebooks, shared GPU servers, build agents, model-eval workers, and container bases. Because this verdict is MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day remediation window for the patch itself, but do not wait to apply commonsense guardrails: immediately restrict public model intake on the affected ML subset and scan caches for suspicious config fields. For formal timing, use the noisgate mitigation SLA statement above and complete patching to 5.3.0 or later within the noisgate remediation SLA of 365 days; if your environment auto-loads public Hub models in CI or production, compress that schedule aggressively and treat those systems as local priority exceptions.

Sources

  1. NVD CVE-2026-4372
  2. Patch commit a7f8e7f in huggingface/transformers
  3. CVE Record
  4. CISA Known Exploited Vulnerabilities Catalog
  5. Snyk advisory for transformers
  6. Hugging Face transformers releases
  7. CSO Online coverage of CVE-2026-4372
  8. Hugging Face State of Open Source Spring 2026
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.