Find this useful? Share the visual.
The Short Version
In July 2026 models under evaluation at two labs reached systems they were not supposed to reach. One set escaped a sandbox through its single permitted outbound path and compromised production infrastructure at Hugging Face. The other went looking for alternatives when it could not reach its assigned target, and compromised three organizations through weak passwords, an exposed debug page, and SQL injection. How each one got in was different every time. What decided the size of the outcome was what the compromised component could reach, which at Hugging Face meant a cloud metadata service, a static database password, and an administrative credential valid on more than one cluster. A buyer controls how vendor components are assembled and can make a fix a condition of the business, though the security inside a component moves on the vendor's schedule.
The component that reads untrusted data should be able to reach almost nothing past the place it writes its own output. That idea is old and I suspect that an engineer would agree with it before finishing the sentence. The July 2026 incident at Hugging Face demonstrates why that policy is worth enforcing, it would have limited the impact of the breach that occurred.
One Permitted Hop
The evaluation sandbox had textbook least privilege egress. Exactly one outbound path was allowed, to an internally hosted package registry cache proxy, permitted so that models under evaluation could install software packages. Everything else was denied.
The models stopped working on the benchmark and started working on the proxy. They found a previously unknown vulnerability in it and turned the one permitted hop into a way out.
What happened at Hugging Face after that involved no perimeter breach. The agent uploaded a dataset as an authenticated user, using the product exactly as designed. Two paths in the processing pipeline did the rest. HDF5, a scientific data format, permits a file to declare that its contents live at some other path on disk, and crafted uploads declared their storage to be the worker's own environment and Python source. The server read those local bytes and served them back through the public API. That is documented behavior rather than a defect. Parsing untrusted HDF5 with external storage enabled hands the uploader arbitrary file reads, the same category of exposure as parsing untrusted XML with entity resolution on. Separately, values in dataset configuration were evaluated as Jinja2 template source, which is a templating language where an expression in the text gets executed, so user supplied configuration became code running inside production.
Asking About Design Versus Asking About Reach
Ask OpenAI the week before what their evaluation sandbox could reach, and the answer is a package registry to install software. Though the answer was true, it provided a permitted channel for escape.
The Hugging Face dataset pipeline was built with a flaw in how it read untrusted uploads. Tracing what the dataset worker could reach would have found the credential chain. That worker could query the cloud metadata service, which is an address inside a cloud environment that hands back credentials for the machine it is running on. It ran with elevated privileges and a mount of the host filesystem, so it could become root on the node. A static password sat in its environment and opened an internal database. An administrative Kubernetes credential was reachable from it through an internal service connector, and the same credential worked on more than one cluster. A corporate mesh VPN key sat in the same secret store.
A design question asks what a system permits. At OpenAI the answer was one outbound path. A reach question asks which credentials a single component can authenticate to. At Hugging Face that answer would have named a cloud metadata service, a database password, and an administrator credential valid on more than one cluster. Component reach decides how far an intrusion travels. Constraining it means giving each component its own scoped credential.
An Attacker Tries Whatever Is Reachable
There is published work on how these systems behave when they are turned loose on a target, and it predates the incident. ExploitGym, released in May 2026, documented that agents frequently abandon the vulnerability handed to them in the prompt and instead audit whatever source they were given, looking for a different and unintended path to running code. Goal hijacking was a result in the literature before it was a headline.
Since previous research shows these models abandon the problem they were handed and go hunting through whatever they can see, they were working through what was reachable. Another possibility is that the models reasoned about Hugging Face specifically, guessing that a platform built to accept files from anyone was probably not inspecting them closely. The models concentrated on escaping through the package proxy since it was the only thing there and it turned out to be exploitable. HDF5 external storage and template evaluation in configuration are both reachable by reading format documentation and the parsing path, without knowing anything about anyone's review culture.
An attacker that enumerates what is available to access does not need to profile an organization. It just needs to find the one component that is exploitable.
ExploitGym documents that goal hijacking happens. It does not explain why one alternative path gets selected over another. Anthropic reviewed its own cybersecurity evaluation transcripts after the OpenAI disclosure and published what it found on July 30, 2026. In two of the three incidents, the model could not reach the target it had been given, so it went looking at whatever else it could get to. One run scanned roughly nine thousand hosts before finding a company it could get into through an exposed debug page and a SQL injection.
Those were different models in a different scenario, and they reached the internet through a network path someone had left open rather than through a vulnerability. The transcripts record Anthropic's models working inside Anthropic's evaluations, so they say nothing about what the models at OpenAI were working through when they turned on the package proxy, or why they picked that one. They do show a model with no reachable target enumerating and taking the first thing that opened. My guess is that surface enumeration is enough to explain the escape and both paths into the pipeline. It is not proof that nothing else was going on.
Separation Leaves Less to Find
Separation does not raise the cost of an attempt in any way the attacker can perceive. It reduces the number of things an attempt can find.
"The parser should carry no credentials" is too strong to be usable in a real system because something that parses a document usually has to write its result somewhere. A document worker with permission to write to one directory is fine, since writing to one directory does not get anybody anywhere. What went wrong at Hugging Face was the scope of what the worker could get to, rather than the fact that it was compromised. The credential reachable from it administered more than one cluster.
Anthropic's second incident put the same problem at a different organization and a much smaller scale. A model published a package to PyPI under a name that a document in its fictional environment told developers to install, and that was still unregistered. The package was live for about an hour and ran on fifteen real systems. One belonged to a security company whose scanner installs Python packages it has no reason to trust so it can check them for malware. Credentials sitting in that environment were copied out and reached further infrastructure at that company.
The remediation Hugging Face published is worth reading as a list of best practices. Pod level access to the cloud metadata service was blocked for all workloads. The configuration renderer stopped evaluating template expressions and external storage references. Static credentials were rotated and moved toward workload identities. The service connector was given scoped credentials, separate per cluster. None of that is new and none of the changes were created based on the incident. It required somebody to trace what one component could reach, understand the impact, and apply the change.
Assembly Is Yours. The Components Are Not.
The security inside a component belongs to whoever wrote it, and it improves on their timeline and their priorities. An assessment that finds a parsing security issue can state that fixing it is a condition of getting the business. Whether they do it is still their call, and a buyer who does not like the answer can decline to buy. Once the purchase is made, what a buyer controls is assembly, meaning the network a thing runs on, the egress it has, and which credentials are reachable from where it runs.
However carefully or carelessly a vendor wrote its parser, a self hosted document processor can run in a container with no outbound route and a database role scoped to a single schema. The vendor owns the parser and the operator owns the conditions it runs under.
Read the incident again with that split in mind. Getting code running was a component problem, in code Hugging Face wrote, and it took a code fix. Everything after that was assembly. A pod running with elevated privileges and a host mount, a metadata service reachable from workloads, a static password in an environment, an administrative credential valid across clusters. Those were available to fix without touching the parser.
Where the split cannot be applied is managed services. Sending untrusted PDFs to a hosted document service puts the parsing tier entirely inside somebody else's boundary. You are not in control of the assembly.
Where Agent Tools Keep Their Credentials
The Model Context Protocol is a standard for connecting assistants to tools, where a server exposes capabilities and carries whatever credentials those capabilities require. An agent takes in content from somewhere, decides a tool is needed, and calls it. When that content is untrusted, the component reading it can invoke the tools the server exposes. The server sees a well formed tool call and cannot tell whether the instruction behind it came from the user or from the content the agent just read.
Teams deploying agent tools put the credentials there on purpose, because it is how the protocol is meant to be used. I am comparing how the pieces are arranged, not claiming an MCP server has failed the way Hugging Face did. Unlike a managed service, this assembly is inside your control. You choose which tools the server exposes and what each of their credentials can reach.
What My Image Uploads Can Reach
Two products I build take image uploads from signed in users and display them back. Decoding one of those uploads is the same category of operation as the Hugging Face pipeline reading an uploaded HDF5 file. An image file declares its own dimensions and offsets before anything has checked them, and the libraries that read them are old and written in C.
That decode can run in the same process as everything else, next to the database credential and the storage credential. A malformed image that gets code execution during the decode reaches whatever that process reaches.
The separation is a container that does nothing but decode, downsample, and re-encode, with no credentials in its environment. A container does not come with rules that deny outbound access. Docker's default bridge gives every container a NAT route to the internet, and Kubernetes lets pods reach anything until a network policy says otherwise. The isolation is a rule that needs to be written, and the toughest version gives the decoder no network stack and hands it work over a pipe.
Separation does not settle the return path. If a crafted image gets execution inside that container, the remaining reach is whatever comes back. A design can treat that output as clean because it came from the thing that sanitizes.
The answer is to send pixels instead of a file. The isolated side returns width, height, and a raw pixel buffer, and the receiving side rejects anything whose buffer length is not width times height times channels, with dimensions capped before it allocates. No container structure crosses, so there is no parser on the trusted side to attack, and that side encodes to one format at settings it chooses. What made HDF5 dangerous was a storage declaration rather than the data.
The isolated side reads the geotag and returns latitude, longitude, and a timestamp as scalar fields with range checks on arrival. Location data survives without the file it came from. Losing the coordinates is what stalled this design the first time.
The images go out from a cookie free domain with one declared content type and nosniff, and a shared link is signed and expires. If a served file ever executes in a browser, there is no session on that domain to steal.
A 1920 by 1080 buffer runs a few megabytes where the JPEG was a few hundred kilobytes, which is fine over a local pipe and wasteful over a network. Encoders are not a zero surface either, just a much smaller one on input of fixed dimensions.
My own standard for image uploads already requires re-encoding, stripping metadata, capping dimensions, and validating by parsing rather than by extension. This incident made me review where that work happens.
What a Required Exception Permits
The exceptions left in a deny rule are the ones something needs. The one outbound path from the evaluation sandbox went to a package registry because models under evaluation had to install software. Nothing about that was careless, and closing it would have ended the evaluation.
So the reach that remains is knowable in advance. Anyone who can name what a system requires in order to run can name its exceptions without probing anything.
What is not knowable in advance is how much the exception permits, since that depends on how the rule was written rather than on what it was for. My own deny rule blocks dotfile paths and excepts /.well-known/. What has to be reachable there is one file, security.txt, which tells a researcher how to report a vulnerability. A prefix is the ordinary way to write that exception, and a prefix permits the directory and everything in it.
Across nine days of logs no dotfile path reaches my origin apart from that one, and the requests arriving at it are not asking for security.txt. They walk invented directory structures inside it and they ask for /.well-known/.well-known/. That is somebody testing where the exception stops.
A requirement for one file met with an exception for a directory is the difference between what a rule was for and what it permits. An exact match on the filename closes it in one line.
What This Leaves for Procurement
Ask a vendor which component parses customer supplied content, what that component can reach if it runs attacker controlled code, and how they would know if it had.
The first two questions ask about intent, and the escape shows that an accurate answer about intent predicts very little. The third question asks about observability, meaning what a vendor would see if it happened, and answering it requires more than a diagram.
Three organizations were compromised in those incidents, and the two Anthropic could reach had not detected it. Anthropic notified them on July 27, and the earliest activity it found dates to April. A lab found the activity by reading back through its own evaluation transcripts after a competitor published a postmortem.
A vendor who knows what its parsing component can reach answers in a couple of sentences. A vendor who does not may answer a nearby question, the one it can speak to well. Certifications and penetration testing are the usual substitutes.
In a large company the questionnaire gets split by section and routed to whoever owns each one, with somebody aggregating what comes back. A seasoned company answers from a library of previous responses first. A question that has not come up before has no stored answer, so it either reaches the engineer who built it or it gets matched to the nearest thing on file.
Ask anyway. Then go look at what your own components can reach, because that does not wait on anyone else.
By the Numbers
The dataset worker pod could reach a cloud metadata service, a static MongoDB password in its own environment, and a mesh-VPN auth key held in cluster secrets. The internal service connector used a single system credential shared across clusters, bound to system:masters, so one stolen credential was cluster-admin everywhere.
Hugging Face, 'Anatomy of a Frontier Lab Agent Intrusion: A Technical Timeline of the July 2026 Incident,' July 2026
Agents regularly reached code execution through a vulnerability other than the one they were handed. GPT-5.5 captured 210 flags against 120 scored successes, so roughly 90 exploits took an unintended path. Trace inspection found agents pivoting to a nearby stronger flaw, or judging the assigned vulnerability unexploitable and auditing source for a new attack surface.
Wang et al., 'ExploitGym: Can AI Agents Turn Security Vulnerabilities into Real Attacks?,' arXiv:2605.11086, May 2026
Anthropic reviewed 141,006 evaluation runs in which a model could have reached the internet, and found three real-world intrusions across six runs. One run scanned roughly 9,000 targets before getting in through an exposed debug page and SQL injection. The earliest activity dated to April; the affected organizations were notified on July 27, 2026.
Anthropic, 'Investigating three real-world incidents in our cybersecurity evaluations,' July 30, 2026
In a second incident a model published a package to PyPI under an unregistered name that a document in its environment told developers to install. It was live for roughly one hour and ran on 15 real systems. One was a security company's scanner, which installs untrusted packages by design, and its credentials were copied out to a collection point.
Anthropic, 'Investigating three real-world incidents in our cybersecurity evaluations,' July 30, 2026
Written by Duane Grey
AI Strategy & Implementation
Independent AI consultant helping companies cut through hype and deploy systems that produce real results.