// blog

Hugging Face's Breach Wasn't Agentic. The Attacker Was.

The July intrusion gets filed under AI security, but the AI was the attacker's tooling and the bug was ordinary code execution. The move worth copying is the one Hugging Face was forced into mid-incident: run your defensive AI local-first, open-weights, and wired to your own logs.

To reconstruct their July intrusion, Hugging Face had more than 17,000 recorded attacker events to sift, so they pointed a frontier model at the logs. The commercial APIs refused. The events were full of real attack commands, exploit payloads, and C2 artifacts, and to a safety filter an incident responder submitting those looks the same as the attacker who authored them. The defenders were locked out of their own investigation. They pivoted to GLM-5.2, an open-weight model run on their own infrastructure, which also kept the attacker’s data and the harvested credentials inside the building.

The refusal layer everyone files under “AI safety” cost the people cleaning up the breach and did nothing to the people who caused it. That’s what I mean when I say refusal is a compliance measure, not a security control: it binds whoever agreed to the terms of service, and the attacker skipped that step.

The agent belonged to the attacker

This is where people reach for the agentic-security shelf: the OWASP Agentic Top 10, prompt injection, tool poisoning, the taxonomy of ways an AI system gets subverted. Wrong shelf. Hugging Face’s own models, agents, and MCP surface came through untouched. The agent here belonged to the attacker — an autonomous offense harness that ran thousands of actions across a swarm of short-lived sandboxes, moved its command-and-control through public services, and drove the intrusion with no human at the keyboard. Hugging Face’s own anomaly detection, itself a model, surfaced it. AI ran on both sides, purely as tooling.

The vulnerability underneath is ordinary. A malicious dataset abused two code-execution paths in the dataset-processing pipeline — a remote-code dataset loader and a template injection in the dataset config — to run code on a processing worker. Mechanically, untrusted input reached a parser that executes it, a bug older than the platform it ran on. The agent added tempo: the same playbook at machine speed and machine cost.

The tempo is this year’s trend line. Check Point’s 2026 AI Security Report describes AI crossing “from assistant to operator” — the model doing the hands-on work inside a live intrusion instead of coaching the human who does. Sysdig documented JADEPUFFER, which it calls the first end-to-end LLM-driven ransomware: an agent that rode a Langflow RCE (CVE-2025-3248) through recon, credential theft, lateral movement, and encryption, and at one point went from a failed login to a working fix in 31 seconds by debugging its own PATH error. Anthropic’s GTG-1002 disclosure put a state-linked actor’s Claude Code agent at 80–90% of the operation against roughly thirty targets, with humans stepping in only at the edges. The Hugging Face swarm is the same pattern aimed at conventional infrastructure: an old bug class with an automated operator.

Code-exec was the match; ambient authority was the accelerant

Code execution on one ingestion worker should be a contained event. It became a production intrusion because of what that worker could reach. From the foothold the agent escalated to node-level access, harvested cloud and cluster credentials, and moved laterally across several internal clusters over a weekend. The confirmed blast radius was a limited set of internal datasets and several service credentials. Public models, datasets, and Spaces came through untouched, and the supply chain verified clean — the good news, and the near miss, because the credential harvest could have gone much further.

Hugging Face left the exploit map out of the writeup, but the hardening patches that landed mid-incident describe it. PR #3368 turns off automatic service-account-token mounting on the worker pods, applies a RuntimeDefault seccomp profile, and drops all Linux capabilities, noting that the worker “never interact[s] with the Kubernetes API” — so it had been carrying an API token it never used. PR #3367 restricts the dataset loader’s fsspec backends to an allowlist and removes the implementations that widen the read surface. PR #3375 moves the production database off a static password onto IAM auth. You harden what was soft, so the picture is a parser that runs untrusted code, standing on an auto-mounted API token, behind a loader that would fetch from nearly anywhere, with long-lived static secrets in reach: a worker with authority well past its job. (The wider reach — cloud metadata endpoint, control-plane path, open egress — is my read from the shape of the fixes and the lateral movement, beyond what Hugging Face stated; treat it as inference.) The code-exec was the match, and the worker’s ambient authority was the accelerant that turned an ingestion incident into a credential harvest across clusters.

This is routine guidance. The NSA/CISA Kubernetes Hardening Guide has said for years to disable the service-account token where a pod stays off the API, scope RBAC to least privilege, and use network policies so a compromise in one namespace stays in one namespace. Hugging Face’s remediation is that guide applied after the fact. These are standard controls, switched on after the breach where they belonged before it.

The wall held where it was deterministic

Every control that contained this was a boundary in code: drop the token, drop the capabilities, allowlist the loader’s protocols, replace static secrets with scoped identity, rebuild compromised nodes from known-good images. It holds because the untrusted thing is structurally unable to reach the thing that matters, and it holds at any attacker speed. That’s the reason I put guardrails in the server and not the prompt, and why the lab I built scores controls by whether the wall holds, not whether the model behaves.

This incident put both kinds of guardrail on the table at once. The refusal kind showed up during forensics, cost the defender time, and left the attacker alone. The confinement kind stopped the code-exec. That’s the one that did the work.

Own the model, or it isn’t yours when it counts

Hugging Face ran GLM-5.2 in-house because the alternative had failed them twice over: a commercial API that refused the work, and an egress path that would have shipped attacker payloads and their own credentials to a third party during a breach. They reached the right architecture under pressure. The catch is that it took the breach to get there.

Every team running security operations should have that capability standing before the next incident: an open-weights model, on infrastructure you control, wired into your log sources and security tools. Make it an analysis layer plumbed into the SIEM, the EDR, the cloud audit trail, and the telemetry, able to query and correlate them and rebuild a timeline at the speed the attack ran.

Local-first and open-weights, for reasons separate from model quality:

  • It answers. No safety policy sits between your responder and the payload they need read, and no vendor rules your forensics too close to an attack to run. Hugging Face lived this one.
  • Your incident data stays put. Logs, credentials, IOCs, C2 artifacts — the most sensitive data you hold — stay inside the boundary. Rent the model and you ship them to a third party to ask about your own breach.
  • It’s always there. No rate limit or vendor outage stands between you and your own logs on the day it matters.
  • You can fit it to your environment — your log formats, your detections, your infrastructure — where a hosted endpoint stays generic.

Same principle applied to the defender’s own tooling: capability lives in the stack you own. A deterministic control you own holds regardless of the attacker. A model you own answers regardless of the vendor. Different tools, same failure under rent — they quit the moment you reach for them, on someone else’s terms.

The tempo is the thing to take from this. Seventeen thousand events in a weekend assumes nobody is watching in time, and a model that fixes its own error in 31 seconds is already past that line. Meeting it means owning the whole defensive stack — the deterministic controls and the AI that watches them — because rented tooling answers to the vendor at the one moment you need it to answer to you.