Back Aikido.Dev Software supply chain security best practices for 2026
In the second quarter of 2026, Aikido Intel analyzed around 7.5 million package versions. Between our automated systems and human researchers, we confirmed 19,500 malicious packages. Attackers have been abusing open source dependencies to get into software, and supply chain attacks began surging in mid-2025. Popular packages like axios and security tools like Trivy and Checkmarx were compromised.
This guide walks through supply chain security best practices that would have stopped the attacks of the past 18 months. If you want a deeper dive, check out the practical checklist for defending against supply chain attacks . The full practical checklist covers 30 controls across containers, CI hardening, and more, graded by priority so you know where to start.
Stop the malware before it installs
Apply a 48-hour minimum package age
A cooldown period blocks any recently published version. Most compromised releases are flagged and pulled within hours of publication, which means a 48-hour gate catches them. The gate puts time between publication and adoption. Enforce it at the private registry or at the package manager. npm has min-release-age since 11.10.0, and Yarn and Bun both ship their own age gates.
Block postinstall hooks with ignore-scripts
You don’t have to use a package for it to run code on your machine, you only have to install it. When you run npm install, npm executes any postinstall script the package author wrote with your privileges. Turn install scripts off with --ignore-scripts and allowlist the handful of packages that genuinely need to compile something. Apply the same setting in CI and on developer machines, to catch credentials that live on the laptop.
The ecosystem defaults are moving in the right direction
pnpm disabled dependency install scripts by default in v10 in January 2025, then turned on a 24-hour cooldown by default in v11 in April 2026. npm v12 shipped on July 8 2026 with dependency install scripts off by default, though your own scripts still run, and it has no default cooldown, so you still set min-release-age yourself. Upgrading your package manager is the cheapest way to cover part of both controls. Teams on older versions and other ecosystems need the explicit settings above. What a cooldown period would have stopped
The axios attacker published a clean decoy, [email protected] , on March 30, then swapped in the malicious [email protected] at 23:59 UTC. Automated detection flagged it six minutes later. [email protected] went live at 00:21 UTC on March 31, and [email protected] followed at 01:00. npm removed both axios versions three hours after the first went live. A 48-hour gate would have kept teams clear of both, with roughly 45 hours to spare.
CanisterWorm republished incremented patch versions of every package its victims maintained, reaching more than 60 packages in 24 hours. Most were flagged within minutes of publication, so a 48-hour gate would have kept them out of your resolver. At least one went undetected for 53 hours, which is why the gate works best alongside install-time malware detection.
Pin anything that can drift
Commit a lockfile and enforce it in your pipeline
A lockfile captures the exact version and integrity hash of every dependency, including transitive ones. Enforcing it means your pipeline runs npm ci rather than npm install, since npm ci installs strictly from the lockfile and fails outright if package.json has drifted away from it. Every other ecosystem has the same mode under a different name, like --frozen-lockfile in pnpm, --immutable in Yarn, --locked in Cargo, and --require-hashes in pip. Make that a required check before merge so the control applies to the whole team.
Pin your pipeline to commit SHAs
Every CI platform lets you pull in dependencies, and in most cases you reference it by a tag or a branch name. Both are pointers that whoever controls the source repo can move at any time. Pinning to a commit SHA removes the possibility of drift, because a SHA refers to one specific tree of code and cannot be repointed. GitHub Actions , GitLab , Buildkite , and Jenkins all accept one in place of a tag. CircleCI works differently, since published orb versions are immutable once released, so an exact version works.
The cost is that you stop receiving upstream fixes automatically, so pair this fix with a bot that opens PRs to move the SHA forward. Renovate handles Actions and GitLab includes among others, and it can do the initial conversion from tags to SHAs for you. Dependabot keeps existing Action pins current but is GitHub Actions only.
Pin base images to digests
A container image tag is a mutable pointer, too. node:22-alpine points at a different image this month than it did last month, and nothing in your Dockerfile records which one you built against.
Pin the FROM line to a digest so the build is reproducible and upstream changes require your approval. Then put a rebuild on an automated schedule, since a pinned digest also means you stop receiving upstream patches until you deliberately move it.
What pinning would have stopped
In March 2025, attackers compromised the tj-actions/changed-files Action and repointed every version tag at a malicious commit that dumped CI secrets into workflow logs. Roughly 23,000 repositories referenced it, and in public repos those logs were readable by anyone.
Every workflow referencing a tag pulled the malicious code on its run. The repositories that had pinned to a commit SHA were untouched.
Lock down access and identity
A token with org-wide publish rights is dangerous because whoever obtains it can publish anything you own. Use fine-grained tokens scoped to specific repositories and packages, and issue a separate credential for each pipeline rather than sharing one across runners and machines. Rotate on a defined schedule and immediately on any suspicion, and revoke the moment someone leaves a project.
A departed CrowdSec developer kept GitHub access to finish some work, and his laptop was compromised in the TanStack attack. An attacker used the token from that machine to clone 170 of CrowdSec’s private repositories in nine minutes. The company found out four months later, when the code appeared on a forum.
Move maintainer accounts to FIDO2 or passkeys
A Time-Based One-Time Password (TOTP) is better than nothing, but it is phishable. An attacker captures the code on a convincing fake login page and replays it on the real site inside the thirty second window, which is enough for an account takeover with no malware involved anywhere. FIDO2 and passkeys are cryptographically bound to the legitimate domain. If you maintain a widely used package, keep the email on the account current and watch it, since npm freezes high-impact accounts for 72 hours after an email swap or a 2FA recovery and sends the alert to the address.
Treat the developer machine like a production environment
Put endpoint detection on every developer machine
A developer laptop holds source code, cloud credentials, publish tokens, and an authenticated session to most of your infrastructure, which is why developer endpoints are now one of the biggest targets of supply chain attacks. Traditional EDR tools catch threats after they are running, which leaves a window where credentials can be lifted or malicious packages installed before anything triggers an alert.
Look for endpoint tools that inspect npm and pip installs at the moment they happen, and that can enforce install-time policies like package age minimums or allowlists for IDE extensions and browser plugins.
Enforce the extension allowlist centrally
IDE extensions and browser plugins run with real privilege and update themselves without asking. Maintain an approved list and push it from a central policy. Our browser extension security guide goes deeper on the browser side specifically.
What this would have stopped
In April 2026, Aikido found a fake WakaTime extension on OpenVSX carrying a native binary that loaded before any legitimate extension logic, pulled a second payload from a GitHub Releases page, and force-installed it into every compatible editor on the machine using each editor’s own command line installer. One install, and VS Code, Cursor, Windsurf, and VSCodium were all infected. A central allowlist would have stopped this, because a fake WakaTime extension published by an unknown account would not be on the approved list.
The limit of an allowlist is that it only helps while an approved extension stays clean. GlassWorm has also compromised legitimate extensions plenty of teams would have approved, and those update themselves with no diff for anyone to review, which is why the install-time layer matters alongside the list.
Scope permissions at configuration time and sandbox the runtime
An agent that can run arbitrary shell commands and reach your production database is one compromised tool call away from a full breach. Grant only the permissions the specific task needs, and review them the way you would review a service account. Then run the agent in a sandbox with network egress controls, so that a compromised agent still cannot reach anything outside the boundary you drew.
Configuration-time scoping and runtime sandboxing solve different halves of the problem. The first limits what the agent is allowed to ask for. The second limits what happens when something gets the agent to ask for more.
Treat MCP servers as dependencies
MCP servers carry the same supply chain risks as any other dependency, so you should only install MCP servers from verified sources such as the official GitHub MCP Registry . For npm-distributed MCP servers, pin via integrity hash in your lockfile. For git-based ones, pin to a full commit SHA rather than a branch or tag. Check that the repository is maintained and the publisher is known before installing. If you're sourcing from a registry, treat an unverified MCP server the same way you would an unverified npm package.
In September 2025, a package called postmark-mcp appeared on npm, impersonating the official MCP server that ActiveCampaign maintains for the Postmark email service. Its job was to let an AI assistant send email through your Postmark account, and for fifteen versions it did exactly that and nothing else. Version 1.0.16 added one line. Every email the server sent was blind-copied to an address the attacker controlled, through the victim’s own account, which meant password resets and invoices and anything else an agent was asked to send went to a stranger as well.
Treat untrusted input reaching an agent as code execution
Aikido’s PromptPwnd research was the first confirmed real-world demonstration of prompt injection compromising CI/CD pipelinesI, affecting at least five Fortune 500 companies. A malicious issue title fed into a Gemini CLI workflow caused the agent to write repository secrets into a public issue thread using its own legitimate access.
Audit any workflow that pipes an issue title or a pull request description into an agent prompt. Treat agent output that reaches a shell command or a file write as untrusted until something validates it.
Detect malicious packages at install time and again in the repository
Coding agents invent package names that sound plausible and do not exist, and attackers have started registering those names in advance and waiting . The agent installs it without a second thought, because the name matches what it expected to find.
Preventing slopsquatting requires malware detection in two places. The first is on the machine, at the moment of install, which catches the agent pulling something during a session and is the same control from the install-time section earlier. The second is in the repository, where a pull request introducing a new dependency gets checked before anyone merges it. The second layer exists because a hallucinated package name can enter the codebase from a developer’s machine that never had the install-time control configured in the first place.
Have a plan for the first hour of a malware attack
Stream your organization audit log to a SIEM. The events worth the most are registry pushes and token use, since those are where a compromise becomes visible before anything else does. For what to alert on specifically, our GitHub Actions security checklist covers the events worth wiring up.
The axios attacker published manually with a long-lived npm token taken from the maintainer’s compromised machine, so there was no suspicious sign-in to find. What gave responders the timeline was the registry record: the account email changing to an attacker-controlled address, then two versions published 39 minutes apart, both timestamped.
Generate signed SBOMs so the exposure question has an answer
When a new CVE drops or a compromised package surfaces, teams without a current software bill of materials (SBOM) spend hours manually tracing dependencies to find out if they're affected. Generate one for every build artifact, including transitive dependencies, since most compromises sit several levels deep. The axios payload arrived through a package nobody had explicitly installed. Sign the SBOM at build time so it is cryptographically bound to the build that produced it, and store it alongside the artifact in your registry so the two stay in sync.
Rehearse the rotation playbook before you need it
Document which credentials rotate for each pipeline and who has the authority to rotate each type. Then write down how you confirm a rotation actually finished, and run the drill. Know your break-glass option in advance. GitHub Enterprise supports bulk credential revocation for a compromised user or for everyone in the enterprise at once. It is blunt, and it beats rotating service by service when you do not yet know how far the compromise reached.
How Aikido Security helps protect against supply chain attacks
Aikido Security covers the install-time and repository layers described in this post. Its detection runs on Aikido Intel, which analyzes all new packages in an average of six minutes and often flags malicious ones within one or two minutes of release.
Device Protection covers what gets installed on developer machines and blocks malicious packages and extensions across the organization. Safe Chain is the free and open-source version for individuals that blocks malicious packages at install time.
The same Aikido Intel detection runs against your repositories, so a malicious dependency that reaches a pull request gets flagged before anyone merges it, including a hallucinated package name that came from a machine without install-time protection. SAST covers the configuration layer, flagging untrusted input flowing into an agent prompt, which is the PromptPwnd pattern.
Get secure today, quickly and for free.
Secure your code, cloud, and runtime in one central system. Connect a repo to discover what the reasoning agents find in your codebase.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
