RC RANDOM CHAOS

Your supply chain isn't compromised. It's working.

Microsoft's open-source developer tools executed credential-stealing code through normal package resolution. The control plane never inspected what was returned.

· 8 min read

Microsoft’s open-source developer tooling, distributed through public package registries and used by AI engineers to build, train, and deploy models, executed code that exfiltrated credentials, API keys, and signing material from developer workstations and build pipelines. The compromise did not begin with an intrusion. It began with a resolution. A package manager looked up a name, retrieved a version, and ran what was returned. The system did exactly what it was designed to do. Telemetry shows no anomaly because no anomaly occurred at the level the telemetry observes. The credential theft was not the result of a bypass. It was the result of an execution path that the system treats as routine.

The affected workstations were not unmanaged. The pipelines were not unmonitored. EDR was present. Endpoint hardening was current. The developers running the tools were experienced. The build systems sat behind identity providers, conditional access, and code-signing policies. None of those controls were defeated, because none of them were positioned to see what was happening. The credential collection ran inside a process whose entire purpose is to fetch and execute remote code. The traffic it generated was indistinguishable from the traffic the same process produces ten thousand times a day across the organization. The behavior was within the envelope the system was built to permit.

What looked like a breach of Microsoft’s tooling was the operation of a supply chain working as specified. A reference was resolved. A package was fetched. Code ran in the context of the developer’s identity and the developer’s access to model weights, training data, cloud secrets, and signing infrastructure. The artifacts produced afterward, the logs, the SBOMs, the dependency manifests, all recorded the event as a successful install. The system did not register a failure because, by its own definitions, nothing had failed.

The original assumption underneath modern developer tooling is that identity of source equals integrity of content. A package name, a maintainer account, a version string, a registry endpoint. These references, once associated with a trusted entity, are treated as durable. The system assumes that the relationship between the name and the bytes it returns is stable across time, across versions, across releases. It assumes that trust granted to a publisher at one moment extends forward to every subsequent artifact that publisher emits, and outward to every dependency that artifact pulls in transitively.

This assumption was reasonable in a smaller world. When the surface area of dependencies was narrow, when maintainers were few and known, when the time between a package’s publication and its consumption was long enough for human inspection to occur, reference and content were tightly coupled. The proxy worked. The name of a package, the identity of its publisher, the reputation of the registry, these served as reliable signals of what the bytes contained. Trust could be delegated to the reference because the reference was anchored in a verifiable artifact. Open source tooling was built on this coupling. Continuous integration was built on it. The entire AI development stack inherited it.

The assumption also extended to the workstation. The developer’s machine assumes that the tools it runs, having been installed and trusted once, remain trustworthy across updates. The build server assumes the same about its dependency graph. The model registry assumes it about the artifacts pushed to it. At every layer, trust is granted to a reference, not to the content the reference resolves to at the moment of execution. The control points are positioned at the boundaries of identity, not at the boundaries of behavior. Authentication is verified. Authorization is checked. What runs after that is treated as legitimate by definition.

What changed is not the sophistication of attackers or the diligence of maintainers. What changed is that references no longer resolve to what they used to resolve to, and the system has no mechanism to notice. A package name today points to a different artifact than it did yesterday. A maintainer account today is controlled by a different entity than it was a month ago. A dependency two layers down today pulls in code that did not exist when the top-level package was last reviewed. The reference is stable. The content behind it is not. The trust relationship the system enforces is the one that no longer corresponds to reality.

The rise of AI development accelerated this drift. The dependency graphs of modern machine learning projects are deeper, wider, and more volatile than those of conventional software. Packages are published, forked, abandoned, and resurrected at a velocity that no human review process can track. Build pipelines pull in new transitive dependencies on every run. Workstations install tools that install other tools. The reference space expanded by orders of magnitude while the validation mechanisms stayed where they were, anchored to publisher identity and version string. The proxy for trust remained the same. The reality the proxy was meant to represent diverged.

The assumption that trust granted once persists forward did not hold. It did not hold for credentials, which were stolen from machines that had been trusted for years. It did not hold for build environments, which executed code that had never been reviewed by anyone inside the organization. It did not hold for the AI artifacts produced afterward, which inherited the compromise from the moment of their construction. The system continued to operate on the assumption. The assumption no longer described the world. The gap between what the system enforced and what was actually true became the operating space for the attacker.

The mechanism is reference replacing validation. When the package manager is asked to install a tool, it does not examine what the tool does. It examines what the tool is called, who claims to have published it, what version number it carries. These references are looked up against a registry, the registry returns a payload, and the payload runs. The control plane is positioned around the reference. The reference is signed, the registry endpoint is authenticated, the publisher account is verified. None of those checks describe the bytes that arrive. They describe the relationship between the request and the response, not between the response and what it actually contains.

A signature on a package proves that someone with control of the publisher’s key signed it. It does not prove the publisher intended to sign it. It does not prove the contents match a previous version. It does not prove the dependencies declared in the manifest are the same dependencies that will execute at install time. The system treats the signature as evidence of integrity because the signature is the only artifact the system can verify. The actual question, what does this code do when it runs, is not in the verification path. It was never in the verification path. The control was designed around the question the system could answer, not the question that mattered.

Identity of source stood in for integrity of content because the cost of resolving identity is bounded and the cost of resolving content is not. A publisher can be identified in milliseconds. A binary cannot be understood in the same time, by the same process, at the same scale. The economic geometry of the supply chain pushed validation onto the only variable that could scale, which was the reference. Every layer above that, the build system, the AI tooling, the workstation, inherited the same compression. The execution of remote code became routine because the validation of remote code had been priced out of the path long before. The credential theft was not a deviation. It was the system executing the only loop it has.

The pattern is execution based on reference, not verification. A name is resolved, an answer is returned, and the system acts on the answer as if the answer were the thing itself. The reference is anchored in a registry. The registry is anchored in a relationship of trust. The trust is anchored in an assumption that the registry’s response corresponds to a stable underlying reality. At each layer, the substitution of reference for content is invisible to the layer above, because the layer above has no language to ask the deeper question. The proxy carries all the weight the system can place on it, and the system places more weight on it every year.

The same mechanism operates in the global routing layer of the internet. A router does not verify that an announced prefix belongs to the entity announcing it. It accepts the announcement, installs the route, and forwards traffic to whatever destination the route describes. The control plane around BGP is positioned at the peering relationship, not at the announcement content. When a network announces a prefix it does not own, the routing fabric does not register an error, because no error has occurred by the system’s own definitions. Traffic flows to the destination the reference resolved to. The systems downstream consume the data they receive as if it came from the intended source, because the only thing they can verify is the path the reference described, not the legitimacy of the announcement that built the path.

The pattern repeats because it is structural. Anywhere a system must operate at a scale where content inspection is impossible, reference resolution takes its place. The reference becomes the unit of trust. The validation collapses onto the metadata around the reference, the signature, the registration, the peering, the certificate, the manifest. The content behind the reference is treated as a consequence of the validated metadata, not as an independent fact requiring its own verification. The system optimized for reference resolution because reference resolution was the only thing it could afford to optimize for. Everything that depends on it inherits the same compression. Every attacker who understands the compression operates inside it.

The system resolves the reference. It does not revalidate what the reference returns. The signature, the registry, the publisher, the version, these are the controls. The credential, the model weight, the signing key, these are the outcomes. The control exists. The outcome does not.

See also: NordVPN for tunneled traffic when operating outside controlled networks.


#ad Contains an affiliate link.

Share

Keep Reading

Stay in the loop

New writing delivered when it's ready. No schedule, no spam.