Supply Chain Attacks Have a New Vector: Plugins

By Trey Annis, Founding Software Engineer

We published a blog post on supply chain attacks earlier this year, emphasizing this quote:

“…Traditional security controls failed because threats arrived through authorized channels using legitimate credentials.”

Supply chain is now an established attack vector, with attackers finding novel ways to compromise parts of the software lifecycle. Innovations to these attacks have made prior third-party dependency safety measures ineffective, as these new attacks are circumventing them entirely. The consistent theme with supply chain exploitation is taking advantage of “authorized channels using legitimate credentials.” In today’s post, we explore a recent supply chain breach. This time, attackers took advantage of Microsoft’s Visual Studio Code plugin marketplace and reportedly stole 3,800 internal company repositories (proprietary source code).

Open-source software (OSS) is embedded in production code across many codebases, from enterprise-level distributed systems to smaller quality-of-life projects for developers, such as a VSCode extension. The most used OSS are battle-tested across decades of fixes from both the owners of the software and the OSS community (think of system utilities like curl). In such cases, the likelihood of a vulnerability in mature software in theory should be lower (there are exceptions). While this assumption is proving less robust with generative AI accelerating the amount of vulnerabilities found across software all across the industry, that is a different subject altogether to be addressed in a separate post. What we want to focus on here is what happens when an OSS release is hijacked: in this case, what happens when a software company’s developer unknowingly installs a poisoned VSCode extension and as a result, opens a backdoor for proprietary software to be stolen? In this mid-dive, we will analyze how this happened; the outcome of the breach; what this could mean for OSS in the future; and potential defense-in-depth mitigations that can be implemented in your organization to further reduce the impact of a poisoned artifact from a software supply chain.

Step 1. The Credential Harvest (Recon)

The first step of a software supply-chain attack is identifying a package as a worthy culprit to be the attack vector. Prior supply-chain attacks such as Shai-Hulud 2.0 aimed at compromising many supply-chain packages in order to have as large of an impact as possible (and in their case, 796 npm packages were compromised). In this case, a single VSCode extension was compromised (a single attack vector) and then installed by an organization employee.

To compromise a supply-chain package requires package registry credentials that authorize the user to publish a new version of that package. Prior recorded supply-chain breaches from this same threat actor report them attaining registry credentials through compromising a GitHub account containing access to those credentials via GitHub secrets. According to Technology.org’s recent post, the attacker’s methodology involves breaching networks where these open-source extensions/packages are being developed. This allows the attacker to stealthily traverse the network, identifying developer credentials that are used to publish each new release of the software. In this case, ArmorCode states that a prior supply chain attack against TanStack harvested a developer’s publishing credentials to a well-known VSCode extension, Nx Console.

Step 2. Authentication (Initial Access)

These captured publishing credentials allowed the attacker to publish a poisoned release of the extension. According to ArmorCode, the release was only live for 18 minutes. That’s all it took for a developer at a large software organization to download the poisoned release. The developer was also likely not aware of the update, as VSCode updates extensions automatically by default.

Step 3. Persistence

The attackers didn’t need any additional steps to establish persistence. For as long as this poisoned version of the release was on the victim’s machine, attackers could act on the victim machine until the malware was removed from the machine—even if the release was only published online for 18 minutes.

Step 4. The route to root (Lateral Movement)

Interestingly, this attack was reported to be strictly non-root—taking advantage only of the compromised user’s permissions. In this case, the developer’s organization granted all developers read-only access to all internal repositories, based on reporting from various sources.

Step 5. Actions on Objective (the end-state)

The objective of this attack was to compromise and exfiltrate internal company data for public consumption, based on various reports observing the attacker publishing the organization’s internal 3,800+ Git repositories for sale. Once the attacker had compromised the victim’s machine, they:

  1. Crawled the machine for all applicable credentials (SSH keys, GitHub credentials)
    • We mentioned in step 4 that this attack was non-root. The attackers not only didn’t need escalated permissions on the host, but not using sudo is another stealthy measure to prevent EDR tools flagging privilege escalation. Furthermore, this crawl was triggered through the extension’s post-install hook (Satine has reported on hooks being used in supply-chain attacks), which prompted generative AI clients on the host (Gemini, Claude, Amazon Q, etc.) to recursively search common locations for credentials. These AI models were prompted specifically to not use sudo.
  2. Packaged up and encrypted all credentials
  3. Uploaded the credentials to an accessible location
    • The credentials that were harvested via those local AI clients on the host were then packaged up, double-encrypted, and posted onto an unassuming public GitHub repository for attackers to access. This is yet another pattern observed by Satine, with GitHub’s own platform functionality being used as part of a supply-chain attack sequence.
  4. Decrypted and utilized applicable credentials to clone 3,800 local copies of company-internal repositories
    • Attackers accessed this public repository containing the credentials, decrypted them, and proceeded to clone all 3,800 repositories using the legitimate now-decrypted developer credentials. It appears that Github utilized their own product’s security features to prevent unauthorized access. Unfortunately, privatizing repositories and authorizing only select groups of users wasn’t enough if the attackers could masquerade as one of these internal users.
  5. Held the data for a time-gated fee, stating that if there wasn’t a buyer then the data would be published regardless
    • Reports state the attackers had put up the 3,800+ repositories on dark-web forums for a time-gated lump-sum price: if there wasn’t a buyer, they would publish it for free anyway.

Questions This Incident Poses

What could this mean for Open-source Software (OSS) moving forward?

Supply chain attacks are becoming not only more common, but mature. Efforts to better track and verify third-party dependencies (such as Software-Bill-Of-Materials (SBOM), private registries, artifact signing, etc.) are implemented to varying degrees across organizations. The problem with solutions like these is that this particular attack circumvented them. These solutions are focused on verifying authenticity and legitimacy of a published dependency; this attack published a legitimate, authentic (albeit, trojanized) release of a VSCode extension with a verified publisher’s credentials. Despite the extension’s seal of approval, 3,800+ repositories were stolen. In general, more scrutiny will need to be applied beyond the authentication and authorization levels of third-party dependency implementation, as recent incidents are showing time and time again that this is no longer enough.

Developer velocity and shipping without friction are common tenets of software engineering organizations, and too many layers of security that create too much friction can go against these tenets. However, the volume of successful supply-chain attack campaigns should prompt the re-evaluation of how OSS, supply chains, and third-party dependencies can best be secured in the face of AI-driven and accelerated threats.

Are there low-hanging-fruit mitigations that could be implemented?

A few things come to mind from the get-go: password-protected SSH keys, adopting the principles of Zero Trust (the IT security model that expects verification from everyone), and implementing a policy that prevents automatic VSCode extension updates. A password-protected key, in the worst case, slows down an attacker; best case, the password complexity makes it impossible to crack and stops the attacker. The most obviously applicable principle to be adopted from Zero Trust is least-privilege: users and groups should be only explicitly granted access to repositories they need (developer velocity will be impacted by this, but we cannot see a world where a developer needs instantaneous, unreviewed access to all 3,800 internal company repositories). Implementing an org-wide policy that prevents automatic extension updates is a quick way to lower the attack efficacy of a poisoned extension by preventing it from installing onto a developer’s machine unknowingly (note: this currently isn’t a built-in enterprise feature, instead the setting must be set directly on local settings. An external enterprise management solution would need to implement the setting on each host’s VSCode local settings. See here); this is akin to version pinning in package ecosystems like npm (package-lock.json) and pypi (requirements.txt or pyproject.toml).

What enterprise-level changes can be made, with defense-in-depth in mind?

We mentioned above that “developer velocity and shipping without friction” are generally prioritized in software engineering organizations, and mitigations at this level should take that into account. We presume with defense-in-depth that the question isn’t “If we get breached…” but “When we get breached…”, so the improvements offered below will be operating under that presumption:

Zero Trust security “implemented” throughout the organization

Developer velocity is at most risk when Zero Trust is implemented poorly: unnecessary segmentation, bogged down process management slowing down request to access, underestimated time-to-implement. The origin of Zero Trust stems from Google’s BeyondCorp, alongside their instructions to implement it, titled Migrating to BeyondCorp: Maintaining Productivity While Improving Security. Bear in mind, the change above has air quotes around the word implement granted Google has claimed themselves in another BeyondCorp publication (here) that:

“Despite all the best efforts to define, roll out, measure, and enforce controls, you may inevitably face the harsh reality that 100% uniform control deployment is a mythical state where unicorns frolic unconcerned about malware and state-sponsored attackers.”

“100% uniform control deployment” is effectively impossible; but a blog post by Maya Kaczorowski boils down general controls that idealistically can get an organization as close as possible to zero-trust. We’ve highlighted a couple here with defense-in-depth in mind that could stop an attacker’s actions on target in the event credentials were taken, while taking into account an organization might be using their own public product (the industry calls this dogfooding) and as a result cannot isolate it to an VPN-guarded intranet:

User authentication, based on single sign-on, and hardware second factors

More layers of authentication should be taking place with these credentials, akin to MFA. SSH keys can be password-protected as stated earlier, but it can go even further with Universal 2nd Factor (U2F) keys, such as YubiKey. Access to protected-resources from here requires something you have on host (stored on the device), something you know (stored in your brain), and something you physically have on your person (stored on your bag or your keychain).

Device authentication, based on a device registry, a hardware-bound device identity, and measured device characteristics like secure boot.

Going even further than a physical U2F key (another form of HSM), access to protected-resources could require a unique signature bound to the host itself through Hardware-Security Modules (HSM). Authenticating would now bind authentication to the specific host. Implementing U2F keys could suffice for this mitigation, with another layer added at the network-security layer that verifies that a request is in fact coming from the employee’s computer and not an unrecognized device.

Higher scrutiny placed on OSS and third-party dependencies

The development of these new and novel supply chain attacks have forced the industry to re-evaluate OSS and third-party dependencies. At the enterprise-level, we suggest:

Mirroring applicable software and package registries

Mirroring these registries offers a few opportunities for extra scrutiny. One, the mirrored registry can be configured to not auto-update packages immediately, preventing an immediate download of potentially compromised software. Two, this introduces the option of performing SAST-style heuristic analysis and vetting of software before it ever reaches the developer’s machine. Heuristic analysis could also implement generative AI that is tuned to look for indicators of unusual behavior within the source.

Assume the risk and adjust accordingly

A lot of our points above have been tangible changes to lower the odds of a breach, but defense-in-depth implies when and not if. Although we can apply scrutiny directly to the source, we only have so much control over the vendor and the systems we put in place to scrutinize the source. Assuming the risk and adjusting accordingly prepares for the inevitable breach, but contains the blast radius; it’s understanding that you don’t have control three-layers up in the chain-of-custody for the dependency or software you are using and preparing accordingly. At the surface, this looks like preventing as much lateral movement as possible and adding gates throughout your organization that stop an attacker from digging further. In the context of developer tools such as a VSCode extension or npm package, that might look like:

  1. A trojanized package has been downloaded and installed by the developer (knowingly or unknowingly). Nestled in the package is a suite of credential harvesting tools.
  2. Those tools begin their attempts to enumerate and collect as many credentials as possible:
  3. A GitHub access token is found and swept up by the tool. However, the token is stale and has expired due to the company’s 24-hour token refresh mandate. It can’t be used for anything.
  4. For some reason, the developer wrote down the PIN to their U2F Yubikey as a text file on their desktop. This Yubikey and associated PIN grants access to the company’s internal suite of package registries and software (something like Artifactory). Jackpot. As it turns out though, this PIN won’t work on its own because access to the company’s internal Artifactory requires the actual YubiKey hardware device be plugged into the developer’s laptop.
  5. A SSH key is collected. Excellent! It’s password-protected, but the credential-harvesting tool is tech-savvy enough to also attempt to brute-force the password. The brute-force was successful and was able to git pull a locally-stored git repository as a smoke test. Let’s now presume the attack commences the same way as the attack above through encryption of the key, upload to a public repository, the attacker downloads and decrypts and has the SSH key in hand. They find out they can only exfiltrate a few repositories before the key entirely stops working altogether due to a heuristic network policy detecting unusual network traffic from an unrecognized host from an unrecognized location. Not only that, but the developer who was issued the SSH key only had access to 3 repositories due to the Zero-Trust implementation requiring least privilege where applicable.

Security, Actually spelled this out very succinctly:

“You make sure that when [the trusted thing] fails, it doesn’t take everything with it.”

Until next time.

Sources

Final CTA Section
GET STARTED

Ready to Strengthen Your Defenses?

Whether you need to test your security posture, respond to an active incident, or prepare your team for the worst: we’re ready to help.

📍 Based in Atlanta | Serving Nationwide

Discover more from Satine Technologies

Subscribe now to keep reading and get access to the full archive.

Continue reading