An attacker flooded a repo with 36 junk pull requests to hide one malicious PR. It worked. Why review fatigue became the attack surface in 2026, and what changed on npm this month.
On July 14, someone opened 37 pull requests against the AsyncAPI generator repository.
Nearly all of them were junk. According to Wiz's red team analysis, most tried to add a fake charity donation page. Low effort, obviously noise, the kind of thing a maintainer skims past and closes.
One of them was not noise. It exploited a misconfigured GitHub Actions workflow to steal a highly privileged personal access token.
The other 36 were camouflage.
Within roughly ninety minutes, per Microsoft Threat Intelligence, five package versions across four package names were republished under the @asyncapi namespace, each carrying the same injected loader. Combined, those packages see over three million downloads a week. And because @asyncapi/specs is a transitive dependency of a lot of AsyncAPI tooling, the blast radius covered developer laptops, CI pipelines, container builds, and any production service that resolved an affected version during the window.
One more detail worth noting. The payload did not run at install time, which is where most tooling watches. It ran at import.
Here is what makes this incident worth an entire edition.
The attacker did not find a clever zero day. They found a workflow misconfiguration, which is common, and then they solved the harder problem: getting a human to not look carefully.
Thirty six worthless pull requests is a deliberate design choice. It is engineered review fatigue. Flood the queue with obvious garbage, and the reviewer shifts into skim mode. Skim mode is the vulnerability.
Which raises an uncomfortable question for every team reading this. How overloaded is your review queue right now?
This newsletter covered the data on that in May. Faros AI's analysis of 22,000 developers found that teams with high AI adoption merge 98% more pull requests, spend 91% longer in review, and interact with 47% more pull requests per day. Review volume went up sharply across the industry, and reviewer capacity did not.
Our read: attackers noticed. The most reliable weakness in a modern engineering org is not the code. It is the finite attention of the people approving it, and that attention has been getting thinner every quarter.
AsyncAPI was not an isolated event. A partial list from public reporting this year:
Axios, on March 31. Microsoft attributed the compromise to Sapphire Sleet, a North Korean state actor also tracked as BlueNoroff. They hijacked the lead maintainer's npm account and injected a malicious dependency into a library with roughly 100 million weekly downloads.
The @redhat-cloud-services namespace on June 1, where Unit 42 reports at least 32 packages were compromised by a payload called Miasma, bypassing code review entirely.
jscrambler on July 11, where Socket found a preinstall hook dropping hidden native binaries for Linux, macOS, and Windows. Detection took six minutes. The interesting part is the target list, which included cloud credentials, crypto wallets, and AI coding assistant credentials. Then the campaign adapted and moved off the install hook to import time, which is the same evasion AsyncAPI used three days later.
And running underneath all of it, the Shai-Hulud worm family, which Unit 42 has tracked through multiple waves this year, at one point reaching packages with billions of combined weekly downloads by self propagating through stolen publish tokens.
To be fair to the maintainers in every one of these stories: these are mostly volunteers running critical infrastructure with no security budget. Blaming them misreads the problem. The registries were built on a trust model from a smaller era, and attackers industrialized against it faster than the tooling adapted.
On July 28, GitHub published a summary of the hardening it has shipped across npm and Actions. Several of these are already live, and one is going to break builds.
npm v12 disables install scripts by default. It also disables dependencies sourced from git or remote URLs by default. Install scripts have legitimate uses, so you can re-enable specific approved ones, but the default flips. If your build depends on postinstall behavior and nobody has audited that, you will find out the hard way.
Dependabot now applies a three day cooldown on version updates by default, as of July 14. The logic is that attackers depend on speed, so delaying non-critical version bumps gives detection signals time to surface. Security updates still open immediately.
Staged publishing arrived in May. Credentials alone are no longer enough to publish; a staged release requires separate approval and 2FA. This is opt in, and if you publish packages it is worth turning on.
High impact npm accounts now enter a 72 hour read only state after an email change or 2FA recovery code use, which is aimed squarely at the phishing step that starts most of these attacks.
On the Actions side, the default behavior of actions/checkout changed to block checkout of untrusted fork code in commonly exploited triggers, the Actions cache is now read only for untrusted triggers, and there are new policies governing who can trigger workflows at all.
GitHub's own guidance on priority is direct: the single highest value action is removing long lived credentials from your CI/CD pipeline, using trusted publishing instead.
None of this requires a security team. It requires someone to sit down for an afternoon and do unglamorous work.
Audit what install scripts your build actually depends on, before npm v12 makes that discovery involuntary. Get long lived npm tokens out of CI and move to trusted publishing. Leave the Dependabot cooldown on rather than reflexively disabling it because it slows your dependency PRs. If you publish anything, turn on staged publishing. Review any workflow using pull_request_target, which is the pattern behind a large share of these initial compromises. And know, before you need it, how you would revoke every credential fast, since self service revocation now exists.
Then the harder one, which is not a setting. Look at what your review queue actually looks like on a Thursday afternoon, and ask honestly whether a well camouflaged pull request would get real scrutiny or a fast approval.
At a ten person company, none of this is anyone's job.
There is no platform team, no security engineer, no one who owns the pipeline. It gets handled by whoever has time, which means it gets handled when something breaks. And this specific work has a bad shape for small teams: it is not urgent until it is catastrophic, it is invisible when done well, and it needs someone who has actually hardened a pipeline before rather than someone reading a checklist for the first time.
That surface area problem is one we wrote about back in March. AI compressed how fast you can build. It did not shrink the number of systems around the build that still need an owner.
The engineers we embed spend a lot of their time on exactly this: pipelines, credentials, deploy safety, the parts of the system that never appear on a roadmap and quietly decide whether a bad Tuesday becomes a bad quarter. Not permanent headcount for a problem that comes in bursts. Someone senior, for the stretch where it matters.
The attackers in July did not break anything sophisticated. They just correctly guessed that nobody was watching closely.
© 2026 Percime Technologies. All rights reserved.